
<!DOCTYPE html>

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>tigramite.lpcmci &#8212; Tigramite 5.2 documentation</title>
    <link rel="stylesheet" type="text/css" href="../../_static/pygments.css" />
    <link rel="stylesheet" type="text/css" href="../../_static/alabaster.css" />
    <script data-url_root="../../" id="documentation_options" src="../../_static/documentation_options.js"></script>
    <script src="../../_static/jquery.js"></script>
    <script src="../../_static/underscore.js"></script>
    <script src="../../_static/_sphinx_javascript_frameworks_compat.js"></script>
    <script src="../../_static/doctools.js"></script>
    <link rel="index" title="Index" href="../../genindex.html" />
    <link rel="search" title="Search" href="../../search.html" />
   
  <link rel="stylesheet" href="../../_static/custom.css" type="text/css" />
  
  
  <meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />

  </head><body>
  

    <div class="document">
      <div class="documentwrapper">
        <div class="bodywrapper">
          

          <div class="body" role="main">
            
  <h1>Source code for tigramite.lpcmci</h1><div class="highlight"><pre>
<span></span><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
<span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">product</span><span class="p">,</span> <span class="n">combinations</span>
<span class="kn">from</span> <span class="nn">copy</span> <span class="kn">import</span> <span class="n">deepcopy</span>

<span class="kn">from</span> <span class="nn">.pcmci_base</span> <span class="kn">import</span> <span class="n">PCMCIbase</span>

<div class="viewcode-block" id="LPCMCI"><a class="viewcode-back" href="../../index.html#tigramite.lpcmci.LPCMCI">[docs]</a><span class="k">class</span> <span class="nc">LPCMCI</span><span class="p">(</span><span class="n">PCMCIbase</span><span class="p">):</span>
<span class="w">    </span><span class="sa">r</span><span class="sd">&quot;&quot;&quot; LPCMCI is an algorithm for causal discovery in large-scale times series that allows for latent confounders and</span>
<span class="sd">    learns lag-specific causal relationships. The algorithm is introduced and explained in:</span>

<span class="sd">    [1] Gerhardus, A. &amp; Runge, J. High-recall causal discovery for autocorrelated time series with latent confounders.</span>
<span class="sd">    Advances in Neural Information Processing Systems, 2020, 33.</span>
<span class="sd">    https://proceedings.neurips.cc/paper/2020/hash/94e70705efae423efda1088614128d0b-Abstract.html</span>
<span class="sd">    </span>
<span class="sd">    NOTE: This method is still EXPERIMENTAL since the default settings of hyperparameters are still being fine-tuned.</span>
<span class="sd">    We actually invite feedback on which work best in applications and numerical experiments.</span>
<span class="sd">    The main function, which applies the algorithm, is &#39;run_lpcmci&#39;.</span>

<span class="sd">    Parameters passed to the constructor:</span>

<span class="sd">    - dataframe: Tigramite dataframe object that contains the the time series dataset \bold{X}</span>
<span class="sd">    </span>
<span class="sd">    - cond_ind_test: A conditional independence test object that specifies which conditional independence test CI is to be used</span>
<span class="sd">    </span>
<span class="sd">    - verbosity: Controls the verbose output self.run_lpcmci() and the function it calls.</span>

<span class="sd">    Parameters passed to self.run_lpcmci(): </span>
<span class="sd">    Note: The default values are still being tuned and some parameters might be removed in the future.</span>
<span class="sd">    </span>
<span class="sd">    - link_assumptions: dict or None</span>
<span class="sd">        Two-level nested dictionary such that link_assumptions[j][(i, lag_i)], where 0 &lt;= j, i &lt;= N-1 (with N the number of component</span>
<span class="sd">        time series) and -tau_max &lt;= lag_i &lt;= -tau_min, is a string which specifies background knowledge about the link from X^i_{t+lag_i} to</span>
<span class="sd">        X^j_t. These are the possibilities for this string and the corresponding claim:</span>
<span class="sd">            </span>
<span class="sd">            &#39;-?&gt;&#39;   : X^i_{t+lag_i} is an ancestor of X^j_t.</span>
<span class="sd">            &#39;--&gt;&#39;   : X^i_{t+lag_i} is an ancestor of X^j_t, and there is a link between X^i_{t+lag_i} and X^j_t</span>
<span class="sd">            &#39;&lt;?-&#39;   : Only allowed for lag_i = 0. X^j_t is an ancestor of X^i_t.</span>
<span class="sd">            &#39;&lt;--&#39;   : Only allowed for lag_i = 0. X^j_t is an ancestor of X^i_t, and there is a link between X^i_t and X^j_t</span>
<span class="sd">            &#39;&lt;?&gt;&#39;   : Neither X^i_{t+lag_i} is an ancestor of X^j_t nor the other way around</span>
<span class="sd">            &#39;&lt;-&gt;&#39;   : Neither X^i_{t+lag_i} is an ancestor of X^j_t nor the other way around, and there is a link between X^i_{t+lag_i} and X^j_t</span>
<span class="sd">            &#39;o?&gt;&#39;   : X^j_t is not an ancestor of X^i_{t+lag_i} (for lag_i &lt; 0 this background knowledge is (for the default settings of self.run_lpcmci()) imposed automatically)</span>
<span class="sd">            &#39;o-&gt;&#39;   : X^j_t is not an ancestor of X^i_{t+lag_i}, and there is a link between X^i_{t+lag_i} and X^j_t</span>
<span class="sd">            &#39;&lt;?o&#39;   : Only allowed for lag_i = 0. X^i_t is not an ancestor of X^j_t</span>
<span class="sd">            &#39;&lt;-o&#39;   : Only allowed for lag_i = 0. X^i_t is not an ancestor of X^j_t, and there is a link between X^i_t and X^j_t</span>
<span class="sd">            &#39;o-o&#39;   : Only allowed for lag_i = 0. There is a link between X^i_t and X^j_t</span>
<span class="sd">            &#39;o?o&#39;   : Only allowed for lag_i = 0. No claim is made</span>
<span class="sd">            &#39;&#39;      : There is no link between X^i_{t+lag_i} and X^j_t.</span>

<span class="sd">        Another way to specify the absent link is if the form of the link between (i, lag_i) and (j, 0) is not specified by the dictionary, that is, if either</span>
<span class="sd">        link_assumptions[j] does not exist or link_assumptions[j] does exist but link_assumptions[j][(i, lag_i)] does</span>
<span class="sd">        not exist, then the link between (i, lag_i) and (j, 0) is assumed to be absent.</span>
<span class="sd">    </span>
<span class="sd">    - tau_min: The assumed minimum time lag, i.e., links with a lag smaller</span>
<span class="sd">      than tau_min are assumed to be absent.</span>
<span class="sd">    </span>
<span class="sd">    - tau_max: The maximum considered time lag, i.e., the algorithm learns a</span>
<span class="sd">      DPAG on a time window [t-\taumax, t] with \tau_max + 1 time steps. It</span>
<span class="sd">      is *not* assumed that in the underlying time series DAG there are no</span>
<span class="sd">      links with a lag larger than \tau_max.</span>
<span class="sd">    </span>
<span class="sd">    - pc_alpha: The significance level of conditional independence tests</span>
<span class="sd">    </span>
<span class="sd">    - n_preliminary_iterations: Determines the number of iterations in the</span>
<span class="sd">      preliminary phase of LPCMCI, corresponding to the &#39;k&#39; in LPCMCI(k) in</span>
<span class="sd">      [1].</span>
<span class="sd">    </span>
<span class="sd">    - max_cond_px: Consider a pair of variables (X^i_{t-\tau}, X^j_t)</span>
<span class="sd">      with \tau &gt; 0. In Algorithm S2 in [1] (here this is</span>
<span class="sd">      self._run_ancestral_removal_phase()), the algorithm does not test for</span>
<span class="sd">      conditional independence given subsets of apds_t(X^i_{t-\tau}, X^j_t, C</span>
<span class="sd">      (G)) of cardinality higher than max_cond_px. In Algorithm S3 in [1]</span>
<span class="sd">      (here this is self._run_non_ancestral_removal_phase()), the algorithm</span>
<span class="sd">      does not test for conditional independence given subsets of napds_t</span>
<span class="sd">      (X^i_{t-\tau}, X^j_t, C(G)) of cardinality higher than max_cond_px.</span>
<span class="sd">    </span>
<span class="sd">    - max_p_global: Restricts all conditional independence tests to</span>
<span class="sd">      conditioning sets with cardinality smaller or equal to max_p_global</span>
<span class="sd">    </span>
<span class="sd">    - max_p_non_ancestral: Restricts all conditional independence tests in the</span>
<span class="sd">      second removal phase (here this is self._run_dsep_removal_phase()) to</span>
<span class="sd">      conditioning sets with cardinality smaller or equal to max_p_global</span>
<span class="sd">    </span>
<span class="sd">    - max_q_global: For each ordered pair (X^i_{t-\tau}, X^j_t) of adjacent</span>
<span class="sd">      variables and for each cardinality of the conditioning sets test at</span>
<span class="sd">      most max_q_global many conditioning sets (when summing over all tested</span>
<span class="sd">      cardinalities more than max_q_global tests may be made)</span>
<span class="sd">    </span>
<span class="sd">    - max_pds_set: In Algorithm S3 (here this is</span>
<span class="sd">      self._run_non_ancestral_removal_phase()), the algorithm tests for</span>
<span class="sd">      conditional independence given subsets of the relevant napds_t sets. If</span>
<span class="sd">      for a given link the set napds_t(X^j_t, X^i_{t-\tau}, C(G)) has more</span>
<span class="sd">      than max_pds_set many elements (or, if the link is also tested in the</span>
<span class="sd">      opposite directed, if napds_t(X^i_{t-\tau}, X^j_t, C(G)) has more than</span>
<span class="sd">      max_pds_set elements), this link is not tested.</span>
<span class="sd">    </span>
<span class="sd">    - prelim_with_collider_rules: If True: As in pseudocode If False: Line 22</span>
<span class="sd">      of Algorithm S2 in [1] is replaced by line 18 of Algorithm S2 when</span>
<span class="sd">      Algorithm S2 is called from the preliminary phase (not in the last</span>
<span class="sd">      application of Algorithm S2 directly before Algorithm S3 is applied)</span>
<span class="sd">    </span>
<span class="sd">    - parents_of_lagged: If True: As in pseudocode If False: The default</span>
<span class="sd">      conditioning set is pa(X^j_t, C(G)) rather than pa({X^j_t, X^i_</span>
<span class="sd">      {t-\tau}, C(G)) for tau &gt; 0</span>
<span class="sd">    </span>
<span class="sd">    - prelim_only: If True, stop after the preliminary phase. Can be used for</span>
<span class="sd">      detailed performance analysis</span>
<span class="sd">    </span>
<span class="sd">    - break_once_separated: If True: As in pseudocode If False: The break</span>
<span class="sd">      commands are removed from Algorithms S2 and S3 in in [1]</span>
<span class="sd">    </span>
<span class="sd">    - no_non_ancestral_phase: If True, do not execute Algorithm S3. Can be</span>
<span class="sd">      used for detailed performance analysis</span>
<span class="sd">    </span>
<span class="sd">    - use_a_pds_t_for_majority: If True: As in pseudocode If False: The search</span>
<span class="sd">      for separating sets instructed by the majority rule is made given</span>
<span class="sd">      subsets adj(X^j_t, C(G)) rather than subsets of apds_t(X^j_t, X^i_</span>
<span class="sd">      {t-\tau}, C(G))</span>
<span class="sd">    </span>
<span class="sd">    - orient_contemp:</span>
<span class="sd">        If orient_contemp == 1: As in pseudocode of Algorithm S2 in [1]</span>
<span class="sd">        If orient_contemp == 2: Also orient contemporaneous links in line 18 of Algorithm S2</span>
<span class="sd">        If orient_comtemp == 0: Also not orient contemporaneous links in line 22 of Algorithm S2</span>
<span class="sd">    </span>
<span class="sd">    - update_middle_marks:</span>
<span class="sd">        If True: As in pseudoce of Algorithms S2 and S3 in [1]</span>
<span class="sd">        If False: The MMR rule is not applied</span>
<span class="sd">    </span>
<span class="sd">    - prelim_rules:</span>
<span class="sd">        If prelim_rules == 1: As in pseudocode of Algorithm S2 in [1]</span>
<span class="sd">        If prelim_rules == 0: Exclude rules R9^prime and R10^\prime from line 18 in Algorithm S2</span>
<span class="sd">    </span>
<span class="sd">    - fix_all_edges_before_final_orientation: When one of max_p_global,</span>
<span class="sd">      max_p_non_ancestral, max_q_global or max_pds_set is not np.inf, the</span>
<span class="sd">      algorithm may terminate although not all middle marks are empty. All</span>
<span class="sd">      orientation rules are nevertheless sound, since the rules always check</span>
<span class="sd">      for the appropriate middle marks. If</span>
<span class="sd">      fix_all_edges_before_final_orientation is True, all middle marks are</span>
<span class="sd">      set to the empty middle mark by force, followed by another application</span>
<span class="sd">      of the rules.</span>
<span class="sd">    </span>
<span class="sd">    - auto_first: If True: As in pseudcode of Algorithms S2 and S3 in [1] If</span>
<span class="sd">      False: Autodependency links are not prioritized even before</span>
<span class="sd">      contemporaneous links</span>
<span class="sd">    </span>
<span class="sd">    - remember_only_parents:</span>
<span class="sd">        If True: As in pseudocode of Algorithm 1</span>
<span class="sd">        If False: If X^i_{t-\tau} has been marked as ancestor of X^j_t at any point of a preliminary iteration but the link between</span>
<span class="sd">        X^i_{t-\tau} and X^j_t was removed later, the link is nevertheless initialized with a tail at X^i_{t-\tau} in the re-initialization</span>
<span class="sd">    </span>
<span class="sd">    - no_apr:</span>
<span class="sd">        If no_apr == 0: As in pseudcode of Algorithms S2 and S3 in [1]</span>
<span class="sd">        If no_apr == 1: The APR is not applied by Algorithm S2, except in line 22 of its last call directly before the call of Algorithm S3</span>
<span class="sd">        If no_apr == 2: The APR is never applied</span>

<span class="sd">    Return value of self.run_lpcmci():</span>
<span class="sd">        graph : array of shape (N, N, tau_max+1)</span>
<span class="sd">            Resulting DPAG, representing the learned causal relationships.</span>
<span class="sd">        val_matrix : array of shape (N, N, tau_max+1)</span>
<span class="sd">            Estimated matrix of test statistic values regarding adjacencies.</span>
<span class="sd">        p_matrix : array of shape [N, N, tau_max+1]</span>
<span class="sd">            Estimated matrix of p-values regarding adjacencies.</span>

<span class="sd">    A note on middle marks: For convenience (to have strings of the same</span>
<span class="sd">    lengths) we here internally denote the empty middle mark by &#39;-&#39;.  For</span>
<span class="sd">    post-processing purposes all middle marks are set to the empty middle</span>
<span class="sd">    mark (here &#39;-&#39;).</span>
<span class="sd">    </span>
<span class="sd">    A note on wildcards: The middle mark wildcard \ast and the edge mark</span>
<span class="sd">    wildcard are here represented as &#39;*&#39;&#39;, the edge mark wildcard \star</span>
<span class="sd">    as &#39;+&#39;.</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="p">,</span> <span class="n">cond_ind_test</span><span class="p">,</span> <span class="n">verbosity</span> <span class="o">=</span> <span class="mi">0</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Class constructor. Store:</span>
<span class="sd">                i)      data</span>
<span class="sd">                ii)     conditional independence test object</span>
<span class="sd">                iii)    some instance attributes&quot;&quot;&quot;</span>

        <span class="c1"># Init base class</span>
        <span class="n">PCMCIbase</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataframe</span><span class="o">=</span><span class="n">dataframe</span><span class="p">,</span> 
                        <span class="n">cond_ind_test</span><span class="o">=</span><span class="n">cond_ind_test</span><span class="p">,</span>
                        <span class="n">verbosity</span><span class="o">=</span><span class="n">verbosity</span><span class="p">)</span>

<div class="viewcode-block" id="LPCMCI.run_lpcmci"><a class="viewcode-back" href="../../index.html#tigramite.lpcmci.LPCMCI.run_lpcmci">[docs]</a>    <span class="k">def</span> <span class="nf">run_lpcmci</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span>
                    <span class="n">link_assumptions</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
                    <span class="n">tau_min</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span>
                    <span class="n">tau_max</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> 
                    <span class="n">pc_alpha</span> <span class="o">=</span> <span class="mf">0.05</span><span class="p">,</span>
                    <span class="n">n_preliminary_iterations</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
                    <span class="n">max_cond_px</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span>
                    <span class="n">max_p_global</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">inf</span><span class="p">,</span>
                    <span class="n">max_p_non_ancestral</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">inf</span><span class="p">,</span>
                    <span class="n">max_q_global</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">inf</span><span class="p">,</span>
                    <span class="n">max_pds_set</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">inf</span><span class="p">,</span>
                    <span class="n">prelim_with_collider_rules</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
                    <span class="n">parents_of_lagged</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
                    <span class="n">prelim_only</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
                    <span class="n">break_once_separated</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
                    <span class="n">no_non_ancestral_phase</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>     
                    <span class="n">use_a_pds_t_for_majority</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
                    <span class="n">orient_contemp</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
                    <span class="n">update_middle_marks</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
                    <span class="n">prelim_rules</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
                    <span class="n">fix_all_edges_before_final_orientation</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
                    <span class="n">auto_first</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
                    <span class="n">remember_only_parents</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
                    <span class="n">no_apr</span> <span class="o">=</span> <span class="mi">0</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Run LPCMCI on the dataset and with the conditional independence test passed to the class constructor and with the</span>
<span class="sd">        options passed to this function.&quot;&quot;&quot;</span>

        <span class="c1">#######################################################################################################################</span>
        <span class="c1">#######################################################################################################################</span>
        <span class="c1"># Step 0: Initializations</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_initialize</span><span class="p">(</span><span class="n">link_assumptions</span><span class="p">,</span> <span class="n">tau_min</span><span class="p">,</span> <span class="n">tau_max</span><span class="p">,</span> <span class="n">pc_alpha</span><span class="p">,</span> <span class="n">n_preliminary_iterations</span><span class="p">,</span> <span class="n">max_cond_px</span><span class="p">,</span> <span class="n">max_p_global</span><span class="p">,</span>
            <span class="n">max_p_non_ancestral</span><span class="p">,</span> <span class="n">max_q_global</span><span class="p">,</span> <span class="n">max_pds_set</span><span class="p">,</span> <span class="n">prelim_with_collider_rules</span><span class="p">,</span> <span class="n">parents_of_lagged</span><span class="p">,</span> <span class="n">prelim_only</span><span class="p">,</span>
            <span class="n">break_once_separated</span><span class="p">,</span> <span class="n">no_non_ancestral_phase</span><span class="p">,</span> <span class="n">use_a_pds_t_for_majority</span><span class="p">,</span> <span class="n">orient_contemp</span><span class="p">,</span> <span class="n">update_middle_marks</span><span class="p">,</span>
            <span class="n">prelim_rules</span><span class="p">,</span> <span class="n">fix_all_edges_before_final_orientation</span><span class="p">,</span> <span class="n">auto_first</span><span class="p">,</span> <span class="n">remember_only_parents</span><span class="p">,</span> <span class="n">no_apr</span><span class="p">)</span>

        <span class="c1">#######################################################################################################################</span>
        <span class="c1">#######################################################################################################################</span>
        <span class="c1"># Step 1: Preliminary phases</span>
        <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">n_preliminary_iterations</span><span class="p">):</span>

            <span class="c1"># Verbose output</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">=======================================================&quot;</span><span class="p">)</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;=======================================================&quot;</span><span class="p">)</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Starting preliminary phase </span><span class="si">{:2}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">))</span>

            <span class="c1"># In the preliminary phases, auto-lag links are tested with first priority. Among the auto-lag links, different lags are</span>
            <span class="c1"># not distinguished. All other links have lower priority, among which those which shorter lags have higher priority</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_run_ancestral_removal_phase</span><span class="p">(</span><span class="n">prelim</span> <span class="o">=</span> <span class="kc">True</span><span class="p">)</span>

            <span class="c1"># Verbose output</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">Preliminary phase </span><span class="si">{:2}</span><span class="s2"> complete&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">))</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">Graph:</span><span class="se">\n</span><span class="s2">--------------------------------&quot;</span><span class="p">)</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_print_graph_dict</span><span class="p">()</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;--------------------------------&quot;</span><span class="p">)</span>

            <span class="c1"># When the option self.prelim_only is chosen, do not re-initialize in the last iteration</span>
            <span class="k">if</span> <span class="n">i</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">n_preliminary_iterations</span> <span class="o">-</span> <span class="mi">1</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">prelim_only</span><span class="p">:</span>
                <span class="k">break</span>

            <span class="c1"># Remember ancestorships, re-initialize and re-apply the remembered ancestorships</span>
            <span class="n">def_ancs</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">def_ancs</span>

            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">remember_only_parents</span><span class="p">:</span>
                <span class="n">smaller_def_ancs</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span>
                <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">):</span>
                    <span class="n">smaller_def_ancs</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="p">{(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">in</span> <span class="n">def_ancs</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span> <span class="o">!=</span> <span class="s2">&quot;&quot;</span><span class="p">}</span>
                <span class="n">def_ancs</span> <span class="o">=</span> <span class="n">smaller_def_ancs</span>

            <span class="bp">self</span><span class="o">.</span><span class="n">_initialize_run_memory</span><span class="p">()</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_apply_new_ancestral_information</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="n">def_ancs</span><span class="p">)</span>

        <span class="c1">#######################################################################################################################</span>
        <span class="c1">#######################################################################################################################</span>
        <span class="c1"># Step 2: Full ancestral phase</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">prelim_only</span><span class="p">:</span>

            <span class="c1"># Verbose output</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">=======================================================&quot;</span><span class="p">)</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;=======================================================&quot;</span><span class="p">)</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Starting final ancestral phase&quot;</span><span class="p">)</span>

            <span class="c1"># In the standard ancestral phase, links are prioritized in the same as in the preliminary phases</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_run_ancestral_removal_phase</span><span class="p">()</span>

            <span class="c1"># Verbose output</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">Final ancestral phase complete&quot;</span><span class="p">)</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">Graph:</span><span class="se">\n</span><span class="s2">--------------------------------&quot;</span><span class="p">)</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_print_graph_dict</span><span class="p">()</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;--------------------------------&quot;</span><span class="p">)</span>

        <span class="c1">#######################################################################################################################</span>
        <span class="c1">#######################################################################################################################</span>
        <span class="c1"># Step 3: Non-ancestral phase</span>
        <span class="k">if</span> <span class="p">(</span><span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">prelim_only</span><span class="p">)</span> <span class="ow">and</span> <span class="p">(</span><span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">no_non_ancestral_phase</span><span class="p">):</span>

            <span class="c1"># Verbose output</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">=======================================================&quot;</span><span class="p">)</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;=======================================================&quot;</span><span class="p">)</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Starting non-ancestral phase&quot;</span><span class="p">)</span>

            <span class="c1"># In the non-ancestral phase, large lags are prioritized</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_run_non_ancestral_removal_phase</span><span class="p">()</span>

            <span class="c1"># Verbose output</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">Non-ancestral phase complete&quot;</span><span class="p">)</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">Graph:</span><span class="se">\n</span><span class="s2">--------------------------------&quot;</span><span class="p">)</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_print_graph_dict</span><span class="p">()</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;--------------------------------&quot;</span><span class="p">)</span>

        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">fix_all_edges_before_final_orientation</span><span class="p">:</span>

            <span class="c1"># Verbose output</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">=======================================================&quot;</span><span class="p">)</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;=======================================================&quot;</span><span class="p">)</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Final rule application phase&quot;</span><span class="p">)</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">Setting all middle marks to &#39;-&#39;&quot;</span><span class="p">)</span>

            <span class="bp">self</span><span class="o">.</span><span class="n">_fix_all_edges</span><span class="p">()</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_run_orientation_phase</span><span class="p">(</span><span class="n">rule_list</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_rules_all</span><span class="p">,</span> <span class="n">only_lagged</span> <span class="o">=</span> <span class="kc">False</span><span class="p">)</span>

        <span class="c1">#######################################################################################################################</span>
        <span class="c1">#######################################################################################################################</span>

        <span class="c1"># Verbose output</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
            <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">=======================================================&quot;</span><span class="p">)</span>
            <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;=======================================================&quot;</span><span class="p">)</span>
            <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">LPCMCI has converged&quot;</span><span class="p">)</span>
            <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">Final graph:</span><span class="se">\n</span><span class="s2">--------------------------------&quot;</span><span class="p">)</span>
            <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;--------------------------------&quot;</span><span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_print_graph_dict</span><span class="p">()</span>
            <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;--------------------------------&quot;</span><span class="p">)</span>
            <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;--------------------------------</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span>

            <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Max search set: </span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">max_na_search_set_found</span><span class="p">))</span>
            <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Max na-pds set: </span><span class="si">{}</span><span class="se">\n</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">max_na_pds_set_found</span><span class="p">))</span>

        <span class="c1"># Post processing</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_fix_all_edges</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">graph</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dict2graph</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">pval_max_matrix</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dict_to_matrix</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">pval_max</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="mi">0</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">val_min_matrix</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dict_to_matrix</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">pval_max_val</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="mi">0</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">cardinality_matrix</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dict_to_matrix</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">pval_max_card</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="mi">0</span><span class="p">)</span>

        <span class="c1"># Build and return the return dictionariy</span>
        <span class="n">return_dict</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;graph&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph</span><span class="p">,</span>
                       <span class="s2">&quot;p_matrix&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">pval_max_matrix</span><span class="p">,</span>
                       <span class="s2">&quot;val_matrix&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">val_min_matrix</span><span class="p">}</span>
        <span class="k">return</span> <span class="n">return_dict</span></div>


    <span class="k">def</span> <span class="nf">_initialize</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">link_assumptions</span><span class="p">,</span> <span class="n">tau_min</span><span class="p">,</span> <span class="n">tau_max</span><span class="p">,</span> <span class="n">pc_alpha</span><span class="p">,</span> <span class="n">n_preliminary_iterations</span><span class="p">,</span> <span class="n">max_cond_px</span><span class="p">,</span> <span class="n">max_p_global</span><span class="p">,</span>
        <span class="n">max_p_non_ancestral</span><span class="p">,</span> <span class="n">max_q_global</span><span class="p">,</span> <span class="n">max_pds_set</span><span class="p">,</span> <span class="n">prelim_with_collider_rules</span><span class="p">,</span> <span class="n">parents_of_lagged</span><span class="p">,</span> <span class="n">prelim_only</span><span class="p">,</span>
        <span class="n">break_once_separated</span><span class="p">,</span> <span class="n">no_non_ancestral_phase</span><span class="p">,</span> <span class="n">use_a_pds_t_for_majority</span><span class="p">,</span> <span class="n">orient_contemp</span><span class="p">,</span> <span class="n">update_middle_marks</span><span class="p">,</span> <span class="n">prelim_rules</span><span class="p">,</span>
        <span class="n">fix_all_edges_before_final_orientation</span><span class="p">,</span> <span class="n">auto_first</span><span class="p">,</span> <span class="n">remember_only_parents</span><span class="p">,</span> <span class="n">no_apr</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Function for</span>
<span class="sd">            i)      saving the arguments passed to self.run_lpcmci() as instance attributes</span>
<span class="sd">            ii)     initializing various memory variables for storing the current graph, sepsets etc.</span>
<span class="sd">            &quot;&quot;&quot;</span>

        <span class="c1"># Save the arguments passed to self.run_lpcmci()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">link_assumptions</span> <span class="o">=</span> <span class="n">link_assumptions</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">tau_min</span> <span class="o">=</span> <span class="n">tau_min</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="o">=</span> <span class="n">tau_max</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">pc_alpha</span> <span class="o">=</span> <span class="n">pc_alpha</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">n_preliminary_iterations</span> <span class="o">=</span> <span class="n">n_preliminary_iterations</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">max_cond_px</span> <span class="o">=</span> <span class="n">max_cond_px</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">max_p_global</span> <span class="o">=</span> <span class="n">max_p_global</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">max_p_non_ancestral</span> <span class="o">=</span> <span class="n">max_p_non_ancestral</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">max_q_global</span> <span class="o">=</span> <span class="n">max_q_global</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">max_pds_set</span> <span class="o">=</span> <span class="n">max_pds_set</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">prelim_with_collider_rules</span> <span class="o">=</span> <span class="n">prelim_with_collider_rules</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">parents_of_lagged</span> <span class="o">=</span> <span class="n">parents_of_lagged</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">prelim_only</span> <span class="o">=</span> <span class="n">prelim_only</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">break_once_separated</span> <span class="o">=</span> <span class="n">break_once_separated</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">no_non_ancestral_phase</span> <span class="o">=</span> <span class="n">no_non_ancestral_phase</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">use_a_pds_t_for_majority</span> <span class="o">=</span> <span class="n">use_a_pds_t_for_majority</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">orient_contemp</span> <span class="o">=</span> <span class="n">orient_contemp</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">update_middle_marks</span> <span class="o">=</span> <span class="n">update_middle_marks</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">prelim_rules</span> <span class="o">=</span> <span class="n">prelim_rules</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">fix_all_edges_before_final_orientation</span> <span class="o">=</span> <span class="n">fix_all_edges_before_final_orientation</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">auto_first</span> <span class="o">=</span> <span class="n">auto_first</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">remember_only_parents</span> <span class="o">=</span> <span class="n">remember_only_parents</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">no_apr</span> <span class="o">=</span> <span class="n">no_apr</span>

        <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">pc_alpha</span><span class="p">,</span> <span class="p">(</span><span class="nb">list</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">ndarray</span><span class="p">)):</span>
                <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;pc_alpha must be single float in LPCMCI.&quot;</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">pc_alpha</span> <span class="o">&lt;</span> <span class="mf">0.</span> <span class="ow">or</span> <span class="n">pc_alpha</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;Choose 0 &lt;= pc_alpha &lt;= 1&quot;</span><span class="p">)</span>
            
        <span class="c1"># Check that validity of tau_min and tau_max</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_check_tau_min_tau_max</span><span class="p">()</span>

        <span class="c1"># Check the validity of &#39;link_assumptions&#39;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">link_assumptions</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_check_link_assumptions</span><span class="p">()</span>

        <span class="c1"># Rules to be executed at the end of a preliminary phase</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_rules_prelim_final</span><span class="o">=</span> <span class="p">[[</span><span class="s2">&quot;APR&quot;</span><span class="p">],</span> <span class="p">[</span><span class="s2">&quot;ER-08&quot;</span><span class="p">],</span> <span class="p">[</span><span class="s2">&quot;ER-02&quot;</span><span class="p">],</span> <span class="p">[</span><span class="s2">&quot;ER-01&quot;</span><span class="p">],</span> <span class="p">[</span><span class="s2">&quot;ER-09&quot;</span><span class="p">],</span> <span class="p">[</span><span class="s2">&quot;ER-10&quot;</span><span class="p">]]</span>

        <span class="c1"># Rules to be executed within the while loop of a preliminary phase</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_rules_prelim</span> <span class="o">=</span> <span class="p">[[</span><span class="s2">&quot;APR&quot;</span><span class="p">],</span> <span class="p">[</span><span class="s2">&quot;ER-08&quot;</span><span class="p">],</span> <span class="p">[</span><span class="s2">&quot;ER-02&quot;</span><span class="p">],</span> <span class="p">[</span><span class="s2">&quot;ER-01&quot;</span><span class="p">]]</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">prelim_rules</span> <span class="o">==</span> <span class="mi">0</span> <span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">_rules_prelim_final</span>

        <span class="c1"># Full list of all rules</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_rules_all</span> <span class="o">=</span> <span class="p">[[</span><span class="s2">&quot;APR&quot;</span><span class="p">],</span> <span class="p">[</span><span class="s2">&quot;ER-08&quot;</span><span class="p">],</span> <span class="p">[</span><span class="s2">&quot;ER-02&quot;</span><span class="p">],</span> <span class="p">[</span><span class="s2">&quot;ER-01&quot;</span><span class="p">],</span> <span class="p">[</span><span class="s2">&quot;ER-00-d&quot;</span><span class="p">],</span> <span class="p">[</span><span class="s2">&quot;ER-00-c&quot;</span><span class="p">],</span> <span class="p">[</span><span class="s2">&quot;ER-03&quot;</span><span class="p">],</span> <span class="p">[</span><span class="s2">&quot;R-04&quot;</span><span class="p">],</span> <span class="p">[</span><span class="s2">&quot;ER-09&quot;</span><span class="p">],</span> <span class="p">[</span><span class="s2">&quot;ER-10&quot;</span><span class="p">],</span> <span class="p">[</span><span class="s2">&quot;ER-00-b&quot;</span><span class="p">],</span> <span class="p">[</span><span class="s2">&quot;ER-00-a&quot;</span><span class="p">]]</span>

        <span class="c1"># Initialize various memory variables for storing the current graph, sepsets etc.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_initialize_run_memory</span><span class="p">()</span>

        <span class="c1"># Return</span>
        <span class="k">return</span> <span class="kc">True</span>

    <span class="k">def</span> <span class="nf">_check_tau_min_tau_max</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Check whether the choice of tau_min and tau_max is valid.&quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="mi">0</span> <span class="o">&lt;=</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_min</span> <span class="o">&lt;=</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;tau_min = </span><span class="si">{}</span><span class="s2">, &quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_min</span><span class="p">)</span> <span class="o">+</span> \
                             <span class="s2">&quot;tau_max = </span><span class="si">{}</span><span class="s2">, &quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">)</span> <span class="o">+</span> \
                             <span class="s2">&quot;but 0 &lt;= tau_min &lt;= tau_max required.&quot;</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">_check_link_assumptions</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Check the validity of user-specified &#39;link_assumptions&#39;.</span>

<span class="sd">        The checks assert:</span>
<span class="sd">        - Valid dictionary keys</span>
<span class="sd">        - Valid edge types</span>
<span class="sd">        - That no causal cycle is specified</span>
<span class="sd">        - That no almost causal cycle is specified</span>

<span class="sd">        The checks do not assert that maximality is not violated.&quot;&quot;&quot;</span>

        <span class="c1"># Ancestorship matrices</span>
        <span class="n">ancs_mat_contemp</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">),</span> <span class="n">dtype</span> <span class="o">=</span> <span class="s2">&quot;int32&quot;</span><span class="p">)</span>
        <span class="n">ancs_mat</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="o">*</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="o">+</span> <span class="mi">1</span><span class="p">),</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="o">*</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)),</span> <span class="n">dtype</span> <span class="o">=</span> <span class="s2">&quot;int32&quot;</span><span class="p">)</span>

        <span class="c1"># Run through the outer dictionary</span>
        <span class="k">for</span> <span class="n">j</span><span class="p">,</span> <span class="n">links_j</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">link_assumptions</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>

            <span class="c1"># Check validity of keys of outer dictionary</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="mi">0</span> <span class="o">&lt;=</span> <span class="n">j</span> <span class="o">&lt;=</span> <span class="bp">self</span><span class="o">.</span><span class="n">N</span> <span class="o">-</span> <span class="mi">1</span><span class="p">:</span>
                <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;The argument &#39;link_assumption&#39; must be a &quot;</span>\
                    <span class="s2">&quot;dictionary whose keys are in {0, 1, ..., N-1}, where N &quot;</span>\
                    <span class="s2">&quot;is the number of component time series. Here, &quot;</span>\
                    <span class="sa">f</span><span class="s2">&quot;N = </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="si">}</span><span class="s2">.&quot;</span><span class="p">)</span>

            <span class="c1"># Run through the inner dictionary</span>
            <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="n">link_ij</span> <span class="ow">in</span> <span class="n">links_j</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>

                <span class="c1"># Check validity of keys of inner dictionary</span>
                <span class="k">if</span> <span class="n">i</span> <span class="o">==</span> <span class="n">j</span> <span class="ow">and</span> <span class="n">lag_i</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                    <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;The dictionary &#39;link_assumptions[</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">] &quot;</span>\
                        <span class="sa">f</span><span class="s2">&quot;must not have the key (</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">, 0), because this refers &quot;</span>\
                        <span class="s2">&quot;to a self-link.&quot;</span><span class="p">)</span>

                <span class="k">if</span> <span class="p">(</span><span class="ow">not</span> <span class="p">(</span><span class="mi">0</span> <span class="o">&lt;=</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="bp">self</span><span class="o">.</span><span class="n">N</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
                    <span class="ow">or</span> <span class="ow">not</span> <span class="p">(</span><span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="o">&lt;=</span> <span class="n">lag_i</span> <span class="o">&lt;=</span> <span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_min</span><span class="p">)):</span>
                    <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;All values of &#39;link_assumptions&#39; must &quot;</span>\
                        <span class="s2">&quot;be dictionaries whose keys are of the form (i, &quot;</span>\
                        <span class="s2">&quot;lag_i), where i in {0, 1, ..., N-1} with N the &quot;</span>\
                        <span class="s2">&quot;number of component time series and lag_i in &quot;</span>\
                        <span class="s2">&quot;{-tau_max, ..., -tau_min} with tau_max the maximum &quot;</span>\
                        <span class="s2">&quot;considered time lag and tau_min the minimum assumed &quot;</span>\
                        <span class="sa">f</span><span class="s2">&quot;time lag. Here, N = </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="si">}</span><span class="s2"> and tau_max = &quot;</span>\
                        <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="si">}</span><span class="s2"> and tau_min = </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_min</span><span class="si">}</span><span class="s2">.&quot;</span><span class="p">)</span>

                <span class="c1"># Check for validity of entries. At the same time mark the</span>
                <span class="c1"># ancestorships in ancs_mat_contemp and ancs_mat</span>

                <span class="k">if</span> <span class="n">link_ij</span> <span class="o">==</span> <span class="s2">&quot;&quot;</span><span class="p">:</span>

                    <span class="c1"># Check for symmetry of lag zero links</span>
                    <span class="k">if</span> <span class="n">lag_i</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>

                        <span class="k">if</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">link_assumptions</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="ow">is</span> <span class="kc">None</span>
                            <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">link_assumptions</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">((</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span> <span class="ow">is</span> <span class="kc">None</span>
                            <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">link_assumptions</span><span class="p">[</span><span class="n">i</span><span class="p">][(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)]</span> <span class="o">!=</span> <span class="s2">&quot;&quot;</span><span class="p">):</span>
                            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;The lag zero links specified by &quot;</span>\
                                <span class="s2">&quot;&#39;link_assumptions&#39; must be symmetric: Because&quot;</span>\
                                <span class="sa">f</span><span class="s2">&quot;&#39;link_assumptions&#39;[</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">][(</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="mi">0</span><span class="si">}</span><span class="s2">)] = &#39;&#39;, &quot;</span>\
                                <span class="s2">&quot; there must also be &quot;</span>\
                                <span class="sa">f</span><span class="s2">&quot;&#39;link_assumptions&#39;[</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">][(</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="mi">0</span><span class="si">}</span><span class="s2">)] = &#39;&#39;.&quot;</span><span class="p">)</span>
                    <span class="k">continue</span>

                <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">link_ij</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">3</span><span class="p">:</span>
                    <span class="k">if</span> <span class="n">lag_i</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">:</span>
                        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;Invalid link: &quot;</span>\
                            <span class="sa">f</span><span class="s2">&quot;&#39;link_assumptions&#39;[</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">][(</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">lag_i</span><span class="si">}</span><span class="s2">)] = &quot;</span>\
                            <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">link_ij</span><span class="si">}</span><span class="s2">. Allowed are: &#39;-?&gt;&#39;, &#39;--&gt;&#39;, &#39;&lt;?&gt;&#39;, &quot;</span>\
                            <span class="s2">&quot;&#39;&lt;-&gt;&#39;, &#39;o?&gt;&#39;, &#39;o-&gt;&#39;.&quot;</span><span class="p">)</span>
                    <span class="k">else</span><span class="p">:</span>
                        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;Invalid link: &quot;</span>\
                            <span class="sa">f</span><span class="s2">&quot;&#39;link_assumptions&#39;[</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">][(</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">lag_i</span><span class="si">}</span><span class="s2">)] = &quot;</span>\
                            <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">link_ij</span><span class="si">}</span><span class="s2">. Allowed are: &#39;-?&gt;&#39;, &#39;--&gt;&#39;, &#39;&lt;?&gt;&#39;, &quot;</span>\
                            <span class="s2">&quot;&#39;&lt;-&gt;&#39;, &#39;o?&gt;&#39;, &#39;o-&gt;&#39;, &#39;&lt;?-&#39;, &#39;&lt;--&#39;, &#39;&lt;?o&#39;, &#39;&lt;--&#39;, &quot;</span>\
                            <span class="s2">&quot;&#39;o-o&#39;, &#39;o?o&#39;.&quot;</span><span class="p">)</span>

                <span class="k">if</span> <span class="n">link_ij</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;-&quot;</span><span class="p">:</span>

                    <span class="k">if</span> <span class="n">link_ij</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;&gt;&quot;</span><span class="p">:</span>
                        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;Invalid link: &quot;</span>\
                            <span class="sa">f</span><span class="s2">&quot;&#39;link_assumptions&#39;[</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">][(</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">lag_i</span><span class="si">}</span><span class="s2">)] = &quot;</span>\
                            <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">link_ij</span><span class="si">}</span><span class="s2">. The first character &#39;-&#39;, which says &quot;</span>\
                            <span class="sa">f</span><span class="s2">&quot;that (</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">lag_i</span><span class="si">}</span><span class="s2">) is an ancestor (cause) of &quot;</span>\
                            <span class="sa">f</span><span class="s2">&quot;(</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">, 0). Hence, (</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">, 0) is a non-ancestor &quot;</span>\
                            <span class="sa">f</span><span class="s2">&quot;(non-cause) of (</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">lag_i</span><span class="si">}</span><span class="s2">) and the third &quot;</span>\
                            <span class="s2">&quot;character must be &#39;&gt;&#39;.&quot;</span><span class="p">)</span>

                    <span class="c1"># Mark the ancestorship</span>
                    <span class="k">if</span> <span class="n">lag_i</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                        <span class="n">ancs_mat_contemp</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
                    <span class="k">for</span> <span class="n">Delta_t</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">-</span> <span class="nb">abs</span><span class="p">(</span><span class="n">lag_i</span><span class="p">)):</span>
                        <span class="n">ancs_mat</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="o">*</span><span class="p">(</span><span class="nb">abs</span><span class="p">(</span><span class="n">lag_i</span><span class="p">)</span> <span class="o">+</span> <span class="n">Delta_t</span><span class="p">)</span> <span class="o">+</span> <span class="n">i</span><span class="p">,</span>
                            <span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="o">*</span><span class="n">Delta_t</span> <span class="o">+</span> <span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>

                <span class="k">elif</span> <span class="n">link_ij</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">&quot;&lt;&quot;</span><span class="p">,</span> <span class="s2">&quot;o&quot;</span><span class="p">]:</span>

                    <span class="k">if</span> <span class="n">lag_i</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">:</span>

                        <span class="k">if</span> <span class="n">link_ij</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;&gt;&quot;</span><span class="p">:</span>
                            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;Invalid link: &quot;</span>\
                                <span class="sa">f</span><span class="s2">&quot;&#39;link_assumptions&#39;[</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">][(</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">lag_i</span><span class="si">}</span><span class="s2">)] = &quot;</span>\
                                <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">link_ij</span><span class="si">}</span><span class="s2">. Since </span><span class="si">{</span><span class="n">lag_i</span><span class="si">}</span><span class="s2"> &lt; 0, (</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">, 0) &quot;</span>\
                                <span class="sa">f</span><span class="s2">&quot;cannot be an ancestor (cause) of &quot;</span>\
                                <span class="sa">f</span><span class="s2">&quot;(</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">lag_i</span><span class="si">}</span><span class="s2">). Hence, the third character &quot;</span>\
                                <span class="sa">f</span><span class="s2">&quot;must be &#39;&gt;&#39;.&quot;</span><span class="p">)</span>

                    <span class="k">else</span><span class="p">:</span>

                        <span class="k">if</span> <span class="n">link_ij</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">&quot;-&quot;</span><span class="p">,</span> <span class="s2">&quot;&gt;&quot;</span><span class="p">,</span> <span class="s2">&quot;o&quot;</span><span class="p">]:</span>
                            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;Invalid link: &quot;</span>\
                                <span class="sa">f</span><span class="s2">&quot;&#39;link_assumptions&#39;[</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">][(</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="mi">0</span><span class="si">}</span><span class="s2">)] = &quot;</span>\
                                <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">link_ij</span><span class="si">}</span><span class="s2">. The third character must be one &quot;</span>\
                                <span class="s2">&quot;of the following: 1) &#39;-&#39;, which says that &quot;</span>\
                                <span class="sa">f</span><span class="s2">&quot;(</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">, 0) is an ancestor (cause) of &quot;</span>\
                                <span class="sa">f</span><span class="s2">&quot;(</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="mi">0</span><span class="si">}</span><span class="s2">). 2) &#39;&gt;&#39;, which says that &quot;</span>\
                                <span class="sa">f</span><span class="s2">&quot;(</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">, 0) is a non-ancestor (non-cause) of &quot;</span>\
                                <span class="sa">f</span><span class="s2">&quot;(</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="mi">0</span><span class="si">}</span><span class="s2">). 3) &#39;o&#39;, which says that it is &quot;</span>\
                                <span class="sa">f</span><span class="s2">&quot;unknown whether or not (</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="mi">0</span><span class="si">}</span><span class="s2">) is an &quot;</span>\
                                <span class="sa">f</span><span class="s2">&quot;ancestor (cause) of (</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="mi">0</span><span class="si">}</span><span class="s2">).&quot;</span><span class="p">)</span>

                        <span class="k">if</span> <span class="n">link_ij</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;-&quot;</span><span class="p">:</span>

                            <span class="k">if</span> <span class="n">link_ij</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;&lt;&quot;</span><span class="p">:</span>
                                <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;Invalid link: &quot;</span>\
                                    <span class="sa">f</span><span class="s2">&quot;&#39;link_assumptions&#39;[</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">][(</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="mi">0</span><span class="si">}</span><span class="s2">)] = &quot;</span>\
                                    <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">link_ij</span><span class="si">}</span><span class="s2">. The third character is &#39;-&#39;, &quot;</span>\
                                    <span class="sa">f</span><span class="s2">&quot;which says that (</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="mi">0</span><span class="si">}</span><span class="s2">) is an &quot;</span>\
                                    <span class="sa">f</span><span class="s2">&quot;ancestor (cause) of (</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, 0). Hence, &quot;</span>\
                                    <span class="sa">f</span><span class="s2">&quot;(</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, 0) is a non-ancestor (non-cause) &quot;</span>\
                                    <span class="sa">f</span><span class="s2">&quot;of (</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="mi">0</span><span class="si">}</span><span class="s2">) and the first character &quot;</span>\
                                    <span class="s2">&quot;must be &#39;&lt;&#39;.&quot;</span><span class="p">)</span>

                            <span class="c1"># Mark the ancestorship</span>
                            <span class="n">ancs_mat_contemp</span><span class="p">[</span><span class="n">j</span><span class="p">,</span> <span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
                            <span class="k">for</span> <span class="n">Delta_t</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="o">+</span> <span class="mi">1</span><span class="p">):</span>
                                <span class="n">ancs_mat</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="o">*</span><span class="n">Delta_t</span> <span class="o">+</span> <span class="n">j</span><span class="p">,</span>
                                    <span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="o">*</span><span class="n">Delta_t</span> <span class="o">+</span> <span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>

                <span class="k">else</span><span class="p">:</span>
                    <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Invalid link: &quot;</span>\
                        <span class="sa">f</span><span class="s2">&quot;&#39;link_assumptions&#39;[</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">][(</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">lag_i</span><span class="si">}</span><span class="s2">)] = &quot;</span>\
                        <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">link_ij</span><span class="si">}</span><span class="s2">. The first character must be one of the &quot;</span>\
                        <span class="sa">f</span><span class="s2">&quot;following: 1) &#39;-&#39;, which says that (</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">lag_i</span><span class="si">}</span><span class="s2">) &quot;</span>\
                        <span class="sa">f</span><span class="s2">&quot;is an ancestor (cause) of (</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">, 0). 2) &#39;&lt;&#39;, which &quot;</span>\
                        <span class="sa">f</span><span class="s2">&quot;says that (</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">lag_i</span><span class="si">}</span><span class="s2">) is a non-ancestor &quot;</span>\
                        <span class="sa">f</span><span class="s2">&quot;(non-cause) of (</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">, 0). 3) &#39;o&#39;, which says that it&quot;</span>\
                        <span class="sa">f</span><span class="s2">&quot;is unknown whether or not (</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">lag_i</span><span class="si">}</span><span class="s2">) is an &quot;</span>\
                        <span class="sa">f</span><span class="s2">&quot;ancestor (cause) of (</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="mi">0</span><span class="si">}</span><span class="s2">).&quot;</span><span class="p">)</span>

                <span class="k">if</span> <span class="n">link_ij</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">&quot;-&quot;</span><span class="p">,</span> <span class="s2">&quot;?&quot;</span><span class="p">]:</span>
                    <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;Invalid link: &quot;</span>\
                        <span class="sa">f</span><span class="s2">&quot;&#39;link_assumptions&#39;[</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">][(</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">lag_i</span><span class="si">}</span><span class="s2">)] = &quot;</span>\
                        <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">link_ij</span><span class="si">}</span><span class="s2">. The second character must be one of the &quot;</span>\
                        <span class="s2">&quot;following: 1) &#39;-&#39;, which says that the link &quot;</span>\
                        <span class="sa">f</span><span class="s2">&quot;(</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">lag_i</span><span class="si">}</span><span class="s2">) </span><span class="si">{</span><span class="n">link_ij</span><span class="si">}</span><span class="s2"> (</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">, 0) is definitely &quot;</span>\
                        <span class="s2">&quot;part of the graph. 2) &#39;?&#39;, which says that link &quot;</span>\
                        <span class="s2">&quot;might be but does not need to be part of the graph.&quot;</span><span class="p">)</span>

                <span class="c1"># Check for symmetry of lag zero links</span>
                <span class="k">if</span> <span class="n">lag_i</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>

                    <span class="k">if</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">link_assumptions</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="ow">is</span> <span class="kc">None</span>
                        <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">link_assumptions</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">((</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span> <span class="ow">is</span> <span class="kc">None</span>
                        <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">link_assumptions</span><span class="p">[</span><span class="n">i</span><span class="p">][(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)]</span> <span class="o">!=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_reverse_link</span><span class="p">(</span><span class="n">link_ij</span><span class="p">)):</span>
                        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;The lag zero links specified by &quot;</span>\
                            <span class="s2">&quot;&#39;link_assumptions&#39; must be symmetric: Because &quot;</span>\
                            <span class="sa">f</span><span class="s2">&quot;&#39;link_assumptions&#39;[</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">][(</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="mi">0</span><span class="si">}</span><span class="s2">)] = &quot;</span>\
                            <span class="sa">f</span><span class="s2">&quot;&#39;</span><span class="si">{</span><span class="n">link_ij</span><span class="si">}</span><span class="s2">&#39; there must also be &quot;</span>\
                            <span class="sa">f</span><span class="s2">&quot;&#39;link_assumptions&#39;[</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">][(</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="mi">0</span><span class="si">}</span><span class="s2">)] = &quot;</span>\
                            <span class="sa">f</span><span class="s2">&quot;&#39;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_reverse_link</span><span class="p">(</span><span class="n">link_ij</span><span class="p">)</span><span class="si">}</span><span class="s2">&#39;.&quot;</span><span class="p">)</span>

        <span class="c1"># Check for contemporaneous cycles</span>
        <span class="n">ancs_mat_contemp_to_N</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">matrix_power</span><span class="p">(</span><span class="n">ancs_mat_contemp</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">ancs_mat_contemp_to_N</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;According to &#39;link_assumptions&#39;, there is a &quot;</span>\
                <span class="s2">&quot;contemporaneous causal cycle. Causal cycles are not allowed.&quot;</span><span class="p">)</span>

        <span class="c1"># Check for almost directed cycles</span>
        <span class="n">ancs_mat_summed</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linalg</span><span class="o">.</span><span class="n">inv</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">eye</span><span class="p">(</span><span class="n">ancs_mat</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">dtype</span> <span class="o">=</span> <span class="s2">&quot;int32&quot;</span><span class="p">)</span> <span class="o">-</span> <span class="n">ancs_mat</span><span class="p">)</span>
        <span class="k">for</span> <span class="n">j</span><span class="p">,</span> <span class="n">links_j</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">link_assumptions</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
            <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="n">link_ij</span> <span class="ow">in</span> <span class="n">links_j</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">link_ij</span> <span class="o">!=</span> <span class="s2">&quot;&quot;</span>
                    <span class="ow">and</span> <span class="n">link_ij</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;&lt;&quot;</span>
                    <span class="ow">and</span> <span class="n">ancs_mat_summed</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="o">*</span><span class="nb">abs</span><span class="p">(</span><span class="n">lag_i</span><span class="p">)</span> <span class="o">+</span> <span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">):</span>
                    <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Inconsistency in &#39;link_assumptions&#39;: &quot;</span>\
                        <span class="sa">f</span><span class="s2">&quot;Since &#39;link_assumptions&#39;[</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">][(</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">lag_i</span><span class="si">}</span><span class="s2">)] &quot;</span>\
                        <span class="sa">f</span><span class="s2">&quot;= </span><span class="si">{</span><span class="n">link_ij</span><span class="si">}</span><span class="s2">, variable (</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">lag_i</span><span class="si">}</span><span class="s2">) is a &quot;</span>\
                        <span class="sa">f</span><span class="s2">&quot;non-ancestor (non-cause) of (</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">, 0). At the same &quot;</span>\
                        <span class="s2">&quot;time, however, &#39;link_assumptions&#39; specifies a &quot;</span>\
                        <span class="sa">f</span><span class="s2">&quot;directed path (causal path) from (</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">lag_i</span><span class="si">}</span><span class="s2">) to &quot;</span>\
                        <span class="sa">f</span><span class="s2">&quot;(</span><span class="si">{</span><span class="n">j</span><span class="si">}</span><span class="s2">, 0).&quot;</span><span class="p">)</span>

        <span class="c1"># Replace absent entries by &#39;&#39;</span>
        <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">):</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">link_assumptions</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">j</span><span class="p">)</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">link_assumptions</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="p">{(</span><span class="n">i</span><span class="p">,</span> <span class="o">-</span><span class="n">tau_i</span><span class="p">):</span> <span class="s2">&quot;&quot;</span>
                    <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">tau_i</span><span class="p">)</span> <span class="ow">in</span> <span class="n">product</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">),</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_min</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="o">+</span><span class="mi">1</span><span class="p">))</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">tau_i</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">i</span> <span class="o">!=</span> <span class="n">j</span><span class="p">)}</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">tau_i</span><span class="p">)</span> <span class="ow">in</span> <span class="n">product</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">),</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_min</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="o">+</span><span class="mi">1</span><span class="p">)):</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">tau_i</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">i</span> <span class="o">!=</span> <span class="n">j</span><span class="p">):</span>
                        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">link_assumptions</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="o">-</span><span class="n">tau_i</span><span class="p">))</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
                            <span class="bp">self</span><span class="o">.</span><span class="n">link_assumptions</span><span class="p">[</span><span class="n">j</span><span class="p">][(</span><span class="n">i</span><span class="p">,</span> <span class="o">-</span><span class="n">tau_i</span><span class="p">)]</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>

    <span class="k">def</span> <span class="nf">_initialize_run_memory</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Function for initializing various memory variables for storing the current graph, sepsets etc.&quot;&quot;&quot;</span>
        
        <span class="c1"># Initialize the nested dictionary for storing the current graph.</span>
        <span class="c1"># Syntax: self.graph_dict[j][(i, -tau)] gives the string representing the link from X^i_{t-tau} to X^j_t</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span> <span class="o">=</span> <span class="p">{}</span>
        <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">):</span>

            <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="p">{(</span><span class="n">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">):</span> <span class="s2">&quot;o?o&quot;</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)</span> <span class="k">if</span> <span class="n">j</span> <span class="o">!=</span> <span class="n">i</span><span class="p">}</span>

            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_cond_px</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">update_middle_marks</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">update</span><span class="p">({(</span><span class="n">i</span><span class="p">,</span> <span class="o">-</span><span class="n">tau</span><span class="p">):</span> <span class="s2">&quot;oL&gt;&quot;</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)</span> <span class="k">for</span> <span class="n">tau</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)})</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">update</span><span class="p">({(</span><span class="n">i</span><span class="p">,</span> <span class="o">-</span><span class="n">tau</span><span class="p">):</span> <span class="s2">&quot;o?&gt;&quot;</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)</span> <span class="k">for</span> <span class="n">tau</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)})</span>

        <span class="c1"># Initialize the nested dictionary for storing separating sets</span>
        <span class="c1"># Syntax: self.sepsets[j][(i, -tau)] stores separating sets of X^i_{t-tau} to X^j_t. For tau = 0, i &lt; j.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">sepsets</span> <span class="o">=</span> <span class="p">{</span><span class="n">j</span><span class="p">:</span> <span class="p">{(</span><span class="n">i</span><span class="p">,</span> <span class="o">-</span><span class="n">tau</span><span class="p">):</span> <span class="nb">set</span><span class="p">()</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)</span> <span class="k">for</span> <span class="n">tau</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="k">if</span> <span class="p">(</span><span class="n">tau</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">j</span><span class="p">)}</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)}</span>

        <span class="c1"># Initialize dictionaries for storing known ancestorships, non-ancestorships, and ambiguous ancestorships</span>
        <span class="c1"># Syntax: self.def_ancs[j] contains the set of all known ancestors of X^j_t. Equivalently for the others</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">def_ancs</span> <span class="o">=</span> <span class="p">{</span><span class="n">j</span><span class="p">:</span> <span class="nb">set</span><span class="p">()</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)}</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">def_non_ancs</span> <span class="o">=</span> <span class="p">{</span><span class="n">j</span><span class="p">:</span> <span class="nb">set</span><span class="p">()</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)}</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">ambiguous_ancestorships</span> <span class="o">=</span> <span class="p">{</span><span class="n">j</span><span class="p">:</span> <span class="nb">set</span><span class="p">()</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)}</span>

        <span class="c1"># Initialize nested dictionaries for saving the maximal p-value among all conditional independence tests of a given</span>
        <span class="c1"># pair of variables as well as the corresponding test statistic values and conditioning set cardinalities</span>
        <span class="c1"># Syntax: As for self.sepsets</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">pval_max</span> <span class="o">=</span> <span class="p">{</span><span class="n">j</span><span class="p">:</span> <span class="p">{(</span><span class="n">i</span><span class="p">,</span> <span class="o">-</span><span class="n">tau</span><span class="p">):</span> <span class="o">-</span><span class="n">np</span><span class="o">.</span><span class="n">inf</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)</span> <span class="k">for</span> <span class="n">tau</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="k">if</span> <span class="p">(</span><span class="n">tau</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">j</span><span class="p">)}</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)}</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">pval_max_val</span> <span class="o">=</span> <span class="p">{</span><span class="n">j</span><span class="p">:</span> <span class="p">{(</span><span class="n">i</span><span class="p">,</span> <span class="o">-</span><span class="n">tau</span><span class="p">):</span> <span class="n">np</span><span class="o">.</span><span class="n">inf</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)</span> <span class="k">for</span> <span class="n">tau</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="k">if</span> <span class="p">(</span><span class="n">tau</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">j</span><span class="p">)}</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)}</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">pval_max_card</span> <span class="o">=</span> <span class="p">{</span><span class="n">j</span><span class="p">:</span> <span class="p">{(</span><span class="n">i</span><span class="p">,</span> <span class="o">-</span><span class="n">tau</span><span class="p">):</span> <span class="o">-</span><span class="n">np</span><span class="o">.</span><span class="n">inf</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)</span> <span class="k">for</span> <span class="n">tau</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="k">if</span> <span class="p">(</span><span class="n">tau</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">j</span><span class="p">)}</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)}</span>                                        
        <span class="c1"># Initialize a nested dictionary for caching na-pds-sets</span>
        <span class="c1"># Syntax: self._na_pds_t[(i, t_i)][(j, t_j)] stores na_pds_t((i, t_i), (j, t_j))</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_na_pds_t</span> <span class="o">=</span> <span class="p">{(</span><span class="n">j</span><span class="p">,</span> <span class="o">-</span><span class="n">tau_j</span><span class="p">):</span> <span class="p">{}</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)</span> <span class="k">for</span> <span class="n">tau_j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)}</span>

        <span class="c1"># Initialize a variable for remembering the maximal cardinality among all calculated na-pds-sets, as well as the</span>
        <span class="c1"># maximial cardinality of any search set in the non-ancestral phase</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">max_na_search_set_found</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">max_na_pds_set_found</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span>

        <span class="c1"># Apply the restriction imposed by tau_min</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_apply_tau_min_restriction</span><span class="p">()</span>

        <span class="c1"># Apply the background knowledge given by background_knowledge</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">link_assumptions</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_apply_link_assumptions</span><span class="p">()</span>

        <span class="c1"># Return</span>
        <span class="k">return</span> <span class="kc">True</span>

    <span class="k">def</span> <span class="nf">_apply_tau_min_restriction</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Apply the restrictions imposed by a non-zero tau_min:</span>
<span class="sd">        - Remove all links of lag smaller than tau_min from self.graph_dict</span>
<span class="sd">        - Set the corresponding entries in self.pval_max, self.pval_max_val, and self.pval_max_card to np.inf, -np.inf, np.inf</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="n">tau</span><span class="p">)</span> <span class="ow">in</span> <span class="n">product</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">),</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">),</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_min</span><span class="p">)):</span>
            <span class="k">if</span> <span class="n">tau</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">j</span> <span class="o">!=</span> <span class="n">i</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">j</span><span class="p">][(</span><span class="n">i</span><span class="p">,</span> <span class="o">-</span><span class="n">tau</span><span class="p">)]</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>

            <span class="k">if</span> <span class="n">tau</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">j</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">pval_max</span><span class="p">[</span><span class="n">j</span><span class="p">][(</span><span class="n">i</span><span class="p">,</span> <span class="o">-</span><span class="n">tau</span><span class="p">)]</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">inf</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">pval_max_val</span><span class="p">[</span><span class="n">j</span><span class="p">][(</span><span class="n">i</span><span class="p">,</span> <span class="o">-</span><span class="n">tau</span><span class="p">)]</span> <span class="o">=</span> <span class="o">-</span><span class="n">np</span><span class="o">.</span><span class="n">inf</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">pval_max_card</span><span class="p">[</span><span class="n">j</span><span class="p">][(</span><span class="n">i</span><span class="p">,</span> <span class="o">-</span><span class="n">tau</span><span class="p">)]</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">inf</span>

    <span class="k">def</span> <span class="nf">_apply_link_assumptions</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Apply the background knowledge specified by &#39;link_assumptions&#39;:</span>
<span class="sd">        - Write the specified edge types to self.graph_dict</span>
<span class="sd">        - Set the corresponding entries in self.pval_max to np.inf, in self.pval_max_val to -np.inf, and in</span>
<span class="sd">        - to self.pval_max_card to np.inf</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="k">for</span> <span class="n">j</span><span class="p">,</span> <span class="n">links_j</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">link_assumptions</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
            <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="n">link</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">link_assumptions</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>

                <span class="c1"># Apply background knowledge</span>
                <span class="k">if</span> <span class="n">link</span> <span class="o">!=</span> <span class="s2">&quot;&quot;</span> <span class="ow">and</span> <span class="n">link</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;?&quot;</span> <span class="ow">and</span> <span class="n">lag_i</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_cond_px</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">update_middle_marks</span><span class="p">:</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">j</span><span class="p">][(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)]</span> <span class="o">=</span> <span class="n">link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;L&quot;</span> <span class="o">+</span> <span class="n">link</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">j</span><span class="p">][(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)]</span> <span class="o">=</span> <span class="n">link</span>

                <span class="c1"># If background knowledge amounts to absence of link, set the corresponding entries in</span>
                <span class="c1"># self.pval_max to 2, in self.pval_max_val to -np.inf, and in self.pval_max_card to None to np.inf</span>
                <span class="k">if</span> <span class="n">link</span> <span class="o">==</span> <span class="s2">&quot;&quot;</span> <span class="ow">and</span> <span class="p">(</span><span class="n">lag_i</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">j</span><span class="p">):</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">pval_max</span><span class="p">[</span><span class="n">j</span><span class="p">][(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)]</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">inf</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">pval_max_val</span><span class="p">[</span><span class="n">j</span><span class="p">][(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)]</span> <span class="o">=</span> <span class="o">-</span><span class="n">np</span><span class="o">.</span><span class="n">inf</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">pval_max_card</span><span class="p">[</span><span class="n">j</span><span class="p">][(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)]</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">inf</span>

    <span class="k">def</span> <span class="nf">_run_ancestral_removal_phase</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">prelim</span> <span class="o">=</span> <span class="kc">False</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Run an ancestral edge removal phase, this is Algorithm S2&quot;&quot;&quot;</span>

        <span class="c1"># Iterate until convergence</span>
        <span class="c1"># p_pc is the cardinality of the non-default part of the conditioning sets. The full conditioning sets may have</span>
        <span class="c1"># higher cardinality due to default conditioning on known parents</span>
        <span class="n">p_pc</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="n">while_broken</span> <span class="o">=</span> <span class="kc">False</span>
        <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>

            <span class="c1">##########################################################################################################</span>
            <span class="c1">### Run the next removal iteration #######################################################################</span>

            <span class="c1"># Force-quit while loop when p_pc exceeds the limit put by self.max_p_global</span>
            <span class="k">if</span> <span class="n">p_pc</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_p_global</span><span class="p">:</span>
                <span class="n">while_broken</span> <span class="o">=</span> <span class="kc">True</span>
                <span class="k">break</span>

            <span class="c1"># Verbose output</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                <span class="k">if</span> <span class="n">p_pc</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">Starting test phase</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;p = </span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">p_pc</span><span class="p">))</span>

            <span class="c1"># Variables to memorize the occurence and absence of certain events in the below edge removal phase</span>
            <span class="n">has_converged</span> <span class="o">=</span> <span class="kc">True</span>
            <span class="n">any_removal</span> <span class="o">=</span> <span class="kc">False</span>

            <span class="c1"># Generate the prioritized link list</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">auto_first</span><span class="p">:</span>

                <span class="n">link_list</span> <span class="o">=</span> <span class="p">[</span><span class="n">product</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">),</span> <span class="nb">range</span><span class="p">(</span><span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">,</span> <span class="mi">0</span><span class="p">))]</span>
                <span class="n">link_list</span> <span class="o">=</span> <span class="n">link_list</span> <span class="o">+</span> <span class="p">[</span><span class="n">product</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">),</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">),</span> <span class="nb">range</span><span class="p">(</span><span class="o">-</span><span class="n">lag</span><span class="p">,</span> <span class="o">-</span><span class="n">lag</span> <span class="o">+</span> <span class="mi">1</span><span class="p">))</span> <span class="k">for</span> <span class="n">lag</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)]</span>

            <span class="k">else</span><span class="p">:</span>

                <span class="n">link_list</span> <span class="o">=</span> <span class="p">[</span><span class="n">product</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">),</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">),</span> <span class="nb">range</span><span class="p">(</span><span class="o">-</span><span class="n">lag</span><span class="p">,</span> <span class="o">-</span><span class="n">lag</span> <span class="o">+</span> <span class="mi">1</span><span class="p">))</span> <span class="k">for</span> <span class="n">lag</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)]</span>


            <span class="c1"># Run through all elements of link_list. Each element of link_list specifies ordered pairs of variables whose</span>
            <span class="c1"># connecting edges are then subjected to conditional independence tests</span>
            <span class="k">for</span> <span class="n">links</span> <span class="ow">in</span> <span class="n">link_list</span><span class="p">:</span>

                <span class="c1"># Memory variables for storing edges that are marked for removal</span>
                <span class="n">to_remove</span> <span class="o">=</span> <span class="p">{</span><span class="n">j</span><span class="p">:</span> <span class="p">{}</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)}</span>

                <span class="c1"># Iterate through all edges specified by links. Note that since the variables paris are ordered, (A, B) and (B, A)</span>
                <span class="c1"># are seen as different pairs.</span>
                <span class="k">for</span> <span class="n">pair</span> <span class="ow">in</span> <span class="n">links</span><span class="p">:</span>

                    <span class="c1"># Decode the elements of links into pairs of variables (X, Y)</span>
                    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">pair</span><span class="p">)</span> <span class="o">==</span> <span class="mi">2</span><span class="p">:</span>
                        <span class="n">X</span> <span class="o">=</span> <span class="p">(</span><span class="n">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
                        <span class="n">Y</span> <span class="o">=</span> <span class="p">(</span><span class="n">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="mi">0</span><span class="p">)</span>
                    <span class="k">else</span><span class="p">:</span>
                        <span class="n">X</span> <span class="o">=</span> <span class="p">(</span><span class="n">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">pair</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>
                        <span class="n">Y</span> <span class="o">=</span> <span class="p">(</span><span class="n">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mi">0</span><span class="p">)</span>

                        <span class="c1"># Do not test auto-links twice</span>
                        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">auto_first</span> <span class="ow">and</span> <span class="n">X</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="n">Y</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span>
                            <span class="k">continue</span>

                    <span class="c1">######################################################################################################</span>
                    <span class="c1">### Exclusion of links ###############################################################################</span>

                    <span class="c1"># Exclude the current link if ...</span>
                    <span class="c1"># ... X = Y</span>
                    <span class="k">if</span> <span class="n">X</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">X</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="n">Y</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span>
                        <span class="k">continue</span>
                    <span class="c1"># ... X &gt; Y</span>
                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_smaller</span><span class="p">(</span><span class="n">Y</span><span class="p">,</span> <span class="n">X</span><span class="p">):</span>
                        <span class="k">continue</span>

                    <span class="c1"># Get the current link</span>
                    <span class="n">link</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">)</span>

                    <span class="c1"># Moreover exclude the current link if ...</span>
                    <span class="c1"># ... X and Y are not adjacent anymore</span>
                    <span class="k">if</span> <span class="n">link</span> <span class="o">==</span> <span class="s2">&quot;&quot;</span><span class="p">:</span>
                        <span class="k">continue</span>
                    <span class="c1"># ... the link is definitely part of G</span>
                    <span class="k">if</span> <span class="n">link</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;-&quot;</span><span class="p">:</span>
                        <span class="k">continue</span>

                    <span class="c1">######################################################################################################</span>
                    <span class="c1">### Determine  which tests the link will be  subjected to  ###########################################</span>

                    <span class="c1"># Depending on the middle mark on the link between X and Y as well as on some global options, we may not need</span>
                    <span class="c1"># to search for separating set among the potential parents of Y and/or X.</span>
                    <span class="n">test_Y</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">link</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">&quot;R&quot;</span><span class="p">,</span> <span class="s2">&quot;!&quot;</span><span class="p">]</span> <span class="k">else</span> <span class="kc">False</span>
                    <span class="n">test_X</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="p">(</span><span class="n">link</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">&quot;L&quot;</span><span class="p">,</span> <span class="s2">&quot;!&quot;</span><span class="p">]</span> <span class="ow">and</span> <span class="p">(</span><span class="n">X</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">or</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">max_cond_px</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_cond_px</span> <span class="o">&gt;=</span> <span class="n">p_pc</span><span class="p">)))</span> <span class="k">else</span> <span class="kc">False</span>
                    
                    <span class="c1">######################################################################################################</span>
                    <span class="c1">### Preparation PC search set and default conditioning set ###########################################</span>

                    <span class="k">if</span> <span class="n">test_Y</span><span class="p">:</span>
                        <span class="n">S_default_YX</span><span class="p">,</span> <span class="n">S_search_YX</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_default_and_search_sets</span><span class="p">(</span><span class="n">Y</span><span class="p">,</span> <span class="n">X</span><span class="p">,</span> <span class="s2">&quot;ancestral&quot;</span><span class="p">)</span>

                    <span class="k">if</span> <span class="n">test_X</span><span class="p">:</span>
                        <span class="n">S_default_XY</span><span class="p">,</span> <span class="n">S_search_XY</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_default_and_search_sets</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="s2">&quot;ancestral&quot;</span><span class="p">)</span>

                    <span class="c1">######################################################################################################</span>
                    <span class="c1">### Middle mark updates ##############################################################################</span>

                    <span class="n">any_middle_mark_update</span> <span class="o">=</span> <span class="kc">False</span>

                    <span class="c1"># Note: Updating the middle marks here, within the for-loop, does not spoil order independence. In fact, this</span>
                    <span class="c1"># update does not influence the flow of the for-loop at all</span>
                    <span class="k">if</span> <span class="n">test_Y</span><span class="p">:</span>
                        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">S_search_YX</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">p_pc</span><span class="p">:</span>
                            <span class="c1"># Note that X is smaller than Y. If S_search_YX exists and has fewer than p elements, X and Y are not</span>
                            <span class="c1"># d-separated by S \subset Par(Y). Therefore, the middle mark on the edge between X and Y can be updated</span>
                            <span class="c1"># with &#39;R&#39;</span>
                            <span class="bp">self</span><span class="o">.</span><span class="n">_apply_middle_mark</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="s2">&quot;R&quot;</span><span class="p">)</span>
                        <span class="k">else</span><span class="p">:</span>
                            <span class="c1"># Since S_search_YX exists and has hat least p_pc elements, the link between X and Y will be subjected to</span>
                            <span class="c1"># conditional independenc tests. Therefore, the algorithm has not converged yet.</span>
                            <span class="n">has_converged</span> <span class="o">=</span> <span class="kc">False</span>

                    <span class="k">if</span> <span class="n">test_X</span><span class="p">:</span>
                        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">S_search_XY</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">p_pc</span><span class="p">:</span>
                            <span class="c1"># Note that X is smaller than Y. If S_search_XY exists and has fewer than p elements, X and Y are not</span>
                            <span class="c1"># d-separated by S \subset Par(X). Therefore, the middle mark on the edge between X and Y can be updated</span>
                            <span class="c1"># with &#39;L&#39;</span>
                            <span class="bp">self</span><span class="o">.</span><span class="n">_apply_middle_mark</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="s2">&quot;L&quot;</span><span class="p">)</span>
                        <span class="k">else</span><span class="p">:</span>
                            <span class="c1"># Since S_search_YX exists and has hat least p_pc elements, the link between X and Y will be subjected to</span>
                            <span class="c1"># conditional independenc tests. Therefore, the algorithm has not converged yet.</span>
                            <span class="n">has_converged</span> <span class="o">=</span> <span class="kc">False</span>

                    <span class="c1">######################################################################################################</span>

                    <span class="c1">######################################################################################################</span>
                    <span class="c1">### Tests for conditional independence ###############################################################</span>

                    <span class="c1"># If option self.break_once_separated is True, the below for-loops will be broken immediately once a separating set</span>
                    <span class="c1"># has been found. In conjunction with the modified majority rule employed for orienting links, order independence</span>
                    <span class="c1"># (with respect to the index &#39;i&#39; on X^i_t) then requires that the tested conditioning sets are ordered in an order</span>
                    <span class="c1"># independent way. Here, the minimal effect size of previous conditional independence tests serve as an order</span>
                    <span class="c1"># independent order criterion.</span>
                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">break_once_separated</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">np</span><span class="o">.</span><span class="n">isinf</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">max_q_global</span><span class="p">):</span>
                        <span class="k">if</span> <span class="n">test_Y</span><span class="p">:</span>
                            <span class="n">S_search_YX</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_sort_search_set</span><span class="p">(</span><span class="n">S_search_YX</span><span class="p">,</span> <span class="n">Y</span><span class="p">)</span>
                        <span class="k">if</span> <span class="n">test_X</span><span class="p">:</span>
                            <span class="n">S_search_XY</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_sort_search_set</span><span class="p">(</span><span class="n">S_search_XY</span><span class="p">,</span> <span class="n">X</span><span class="p">)</span>

                    <span class="c1"># Run through all cardinality p_pc subsets of S_search_YX</span>
                    <span class="k">if</span> <span class="n">test_Y</span><span class="p">:</span>

                        <span class="n">q_count</span> <span class="o">=</span> <span class="mi">0</span>
                        <span class="k">for</span> <span class="n">S_pc</span> <span class="ow">in</span> <span class="n">combinations</span><span class="p">(</span><span class="n">S_search_YX</span><span class="p">,</span> <span class="n">p_pc</span><span class="p">):</span>

                            <span class="n">q_count</span> <span class="o">=</span> <span class="n">q_count</span> <span class="o">+</span> <span class="mi">1</span>
                            <span class="k">if</span> <span class="n">q_count</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_q_global</span><span class="p">:</span>
                                <span class="k">break</span>

                            <span class="c1"># Build the full conditioning set</span>
                            <span class="n">Z</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">S_pc</span><span class="p">)</span>
                            <span class="n">Z</span> <span class="o">=</span> <span class="n">Z</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="n">S_default_YX</span><span class="p">)</span>

                            <span class="c1"># Test conditional independence of X and Y given Z</span>
                            <span class="n">val</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">dependent</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cond_ind_test</span><span class="o">.</span><span class="n">run_test</span><span class="p">(</span><span class="n">X</span> <span class="o">=</span> <span class="p">[</span><span class="n">X</span><span class="p">],</span> <span class="n">Y</span> <span class="o">=</span> <span class="p">[</span><span class="n">Y</span><span class="p">],</span> <span class="n">Z</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">Z</span><span class="p">),</span> 
                                <span class="n">tau_max</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">,</span> <span class="n">alpha_or_thres</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">pc_alpha</span><span class="p">)</span>

                            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">:</span>
                                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ANC(Y):    </span><span class="si">%s</span><span class="s2"> _|_ </span><span class="si">%s</span><span class="s2">  |  S_def = </span><span class="si">%s</span><span class="s2">, S_pc = </span><span class="si">%s</span><span class="s2">: val = </span><span class="si">%.2f</span><span class="s2"> / pval = </span><span class="si">% .4f</span><span class="s2">&quot;</span> <span class="o">%</span>
                                    <span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="n">S_default_YX</span><span class="p">]),</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="n">S_pc</span><span class="p">]),</span> <span class="n">val</span><span class="p">,</span> <span class="n">pval</span><span class="p">))</span>

                            <span class="c1"># Accordingly update dictionaries that keep track of the maximal p-value and the corresponding test statistic</span>
                            <span class="c1"># values and conditioning set cardinalities</span>
                            <span class="bp">self</span><span class="o">.</span><span class="n">_update_pval_val_card_dicts</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">val</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">Z</span><span class="p">))</span>

                            <span class="c1"># Check whether test result was significant</span>
                            <span class="k">if</span> <span class="ow">not</span> <span class="n">dependent</span><span class="p">:</span> <span class="c1">#pval &gt; self.pc_alpha:</span>

                                <span class="c1"># Mark the edge from X to Y for removal and save sepset</span>
                                <span class="n">to_remove</span><span class="p">[</span><span class="n">Y</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="n">X</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span>
                                <span class="bp">self</span><span class="o">.</span><span class="n">_save_sepset</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="p">(</span><span class="nb">frozenset</span><span class="p">(</span><span class="n">Z</span><span class="p">),</span> <span class="s2">&quot;wm&quot;</span><span class="p">))</span>
            
                                <span class="c1"># Verbose output</span>
                                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                                    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;(</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) </span><span class="si">{:11}</span><span class="s2"> </span><span class="si">{}</span><span class="s2"> given </span><span class="si">{}</span><span class="s2"> union </span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">X</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">X</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s2">&quot;independent&quot;</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">S_pc</span><span class="p">,</span> <span class="n">S_default_YX</span><span class="p">))</span>

                                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">break_once_separated</span><span class="p">:</span>
                                    <span class="k">break</span>

                    <span class="c1"># Run through all cardinality p_pc subsets of S_search_XY</span>
                    <span class="k">if</span> <span class="n">test_X</span><span class="p">:</span>

                        <span class="n">q_count</span> <span class="o">=</span> <span class="mi">0</span>
                        <span class="k">for</span> <span class="n">S_pc</span> <span class="ow">in</span> <span class="n">combinations</span><span class="p">(</span><span class="n">S_search_XY</span><span class="p">,</span> <span class="n">p_pc</span><span class="p">):</span>

                            <span class="n">q_count</span> <span class="o">=</span> <span class="n">q_count</span> <span class="o">+</span> <span class="mi">1</span>
                            <span class="k">if</span> <span class="n">q_count</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_q_global</span><span class="p">:</span>
                                <span class="k">break</span>

                            <span class="c1"># Build the full conditioning set</span>
                            <span class="n">Z</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">S_pc</span><span class="p">)</span>
                            <span class="n">Z</span> <span class="o">=</span> <span class="n">Z</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="n">S_default_XY</span><span class="p">)</span>

                            <span class="c1"># Test conditional independence of X and Y given Z</span>
                            <span class="n">val</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">dependent</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cond_ind_test</span><span class="o">.</span><span class="n">run_test</span><span class="p">(</span><span class="n">X</span> <span class="o">=</span> <span class="p">[</span><span class="n">X</span><span class="p">],</span> <span class="n">Y</span> <span class="o">=</span> <span class="p">[</span><span class="n">Y</span><span class="p">],</span> <span class="n">Z</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">Z</span><span class="p">),</span> 
                                <span class="n">tau_max</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">,</span> <span class="n">alpha_or_thres</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">pc_alpha</span><span class="p">)</span>

                            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">:</span>
                                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ANC(X):    </span><span class="si">%s</span><span class="s2"> _|_ </span><span class="si">%s</span><span class="s2">  |  S_def = </span><span class="si">%s</span><span class="s2">, S_pc = </span><span class="si">%s</span><span class="s2">: val = </span><span class="si">%.2f</span><span class="s2"> / pval = </span><span class="si">% .4f</span><span class="s2">&quot;</span> <span class="o">%</span>
                                    <span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="n">S_default_XY</span><span class="p">]),</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="n">S_pc</span><span class="p">]),</span> <span class="n">val</span><span class="p">,</span> <span class="n">pval</span><span class="p">))</span>

                            <span class="c1"># Accordingly update dictionaries that keep track of the maximal p-value and the corresponding test statistic</span>
                            <span class="c1"># values and conditioning set cardinalities</span>
                            <span class="bp">self</span><span class="o">.</span><span class="n">_update_pval_val_card_dicts</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">val</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">Z</span><span class="p">))</span>

                            <span class="c1"># Check whether test result was significant</span>
                            <span class="k">if</span> <span class="ow">not</span> <span class="n">dependent</span><span class="p">:</span> <span class="c1"># pval &gt; self.pc_alpha:</span>

                                <span class="c1"># Mark the edge from X to Y for removal and save sepset</span>
                                <span class="n">to_remove</span><span class="p">[</span><span class="n">Y</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="n">X</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span>
                                <span class="bp">self</span><span class="o">.</span><span class="n">_save_sepset</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="p">(</span><span class="nb">frozenset</span><span class="p">(</span><span class="n">Z</span><span class="p">),</span> <span class="s2">&quot;wm&quot;</span><span class="p">))</span>
            
                                <span class="c1"># Verbose output</span>
                                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                                    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;(</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) </span><span class="si">{:11}</span><span class="s2"> </span><span class="si">{}</span><span class="s2"> given </span><span class="si">{}</span><span class="s2"> union </span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">X</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">X</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s2">&quot;independent&quot;</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">S_pc</span><span class="p">,</span> <span class="n">S_default_XY</span><span class="p">))</span>

                                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">break_once_separated</span><span class="p">:</span>
                                    <span class="k">break</span>

                <span class="c1"># for pair in links</span>

                <span class="c1">##########################################################################################################</span>
                <span class="c1">### Remove edges marked for removal in to_remove #########################################################</span>

                <span class="c1"># Run through all of the nested dictionary</span>
                <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">):</span>
                    <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">in</span> <span class="n">to_remove</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span>

                        <span class="c1"># Remember that at least one edge has been removed, remove the edge</span>
                        <span class="n">any_removal</span> <span class="o">=</span> <span class="kc">True</span>
                        <span class="bp">self</span><span class="o">.</span><span class="n">_write_link</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">verbosity</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span><span class="p">)</span>

            <span class="c1"># end for links in link_list</span>

            <span class="c1"># Verbose output</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">Test phase complete&quot;</span><span class="p">)</span>

            <span class="c1">##############################################################################################################</span>
            <span class="c1">### Orientations and next step ###############################################################################</span>

            <span class="k">if</span> <span class="n">any_removal</span><span class="p">:</span>
                <span class="c1"># At least one edge was removed or at least one middle mark has been updated. Therefore: i) apply the restricted set of</span>
                <span class="c1"># orientation rules, ii) restart the while loop at p_pc = 0, unless all edges have converged, then break the while loop</span>

                <span class="n">only_lagged</span> <span class="o">=</span> <span class="kc">False</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">orient_contemp</span> <span class="o">==</span> <span class="mi">2</span> <span class="k">else</span> <span class="kc">True</span>
                <span class="n">any_update</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_run_orientation_phase</span><span class="p">(</span><span class="n">rule_list</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_rules_prelim</span><span class="p">,</span> <span class="n">only_lagged</span> <span class="o">=</span> <span class="n">only_lagged</span><span class="p">)</span>

                <span class="c1"># If the orientation phase made a non-trivial update, then restart the while loop. Else increase p_pc by one</span>
                <span class="k">if</span> <span class="n">any_update</span><span class="p">:</span>
                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_cond_px</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">update_middle_marks</span><span class="p">:</span>
                        <span class="bp">self</span><span class="o">.</span><span class="n">_update_middle_marks</span><span class="p">()</span>
                    <span class="n">p_pc</span> <span class="o">=</span> <span class="mi">0</span>

                <span class="k">else</span><span class="p">:</span>
                    <span class="n">p_pc</span> <span class="o">=</span> <span class="n">p_pc</span> <span class="o">+</span> <span class="mi">1</span>

            <span class="k">else</span><span class="p">:</span>
                <span class="c1"># The graph has not changed at all in this iteration of the while loop. Therefore, if all edges have converged, break the</span>
                <span class="c1"># while loop. If at least one edge has not yet converged, increase p_pc by one.</span>

                <span class="k">if</span> <span class="n">has_converged</span><span class="p">:</span>
                    <span class="k">break</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="n">p_pc</span> <span class="o">=</span> <span class="n">p_pc</span> <span class="o">+</span> <span class="mi">1</span>

        <span class="c1"># end while True</span>

        <span class="c1">##################################################################################################################</span>
        <span class="c1">### Consistency test and middle mark update ######################################################################</span>

        <span class="c1"># Run through the entire graph</span>
        <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">):</span>
            <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span>

                <span class="n">X</span> <span class="o">=</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span>
                <span class="n">Y</span> <span class="o">=</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>

                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_smaller</span><span class="p">(</span><span class="n">Y</span><span class="p">,</span> <span class="n">X</span><span class="p">):</span>
                    <span class="k">continue</span>

                <span class="c1"># Consider only those links that are still part G</span>
                <span class="n">link</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
                <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">link</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>

                    <span class="c1"># Consistency check</span>
                    <span class="k">if</span> <span class="ow">not</span> <span class="n">while_broken</span><span class="p">:</span>
                        <span class="k">assert</span> <span class="n">link</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;?&quot;</span>
                        <span class="k">assert</span> <span class="n">link</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;L&quot;</span>
                        <span class="k">assert</span> <span class="p">((</span><span class="n">link</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;R&quot;</span><span class="p">)</span> <span class="ow">or</span> <span class="p">(</span><span class="n">lag_i</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">max_cond_px</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">or</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">update_middle_marks</span><span class="p">))</span>
                            <span class="ow">or</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">no_apr</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">))</span>


                    <span class="c1"># Update all middle marks to &#39;!&#39;</span>
                    <span class="k">if</span> <span class="n">link</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">&quot;-&quot;</span><span class="p">,</span> <span class="s2">&quot;!&quot;</span><span class="p">]:</span>
                        <span class="bp">self</span><span class="o">.</span><span class="n">_write_link</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;!&quot;</span> <span class="o">+</span> <span class="n">link</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>
                    

        <span class="c1">##################################################################################################################</span>
        <span class="c1">### Final rule applications ######################################################################################</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="n">prelim</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">prelim_with_collider_rules</span><span class="p">:</span>

            <span class="k">if</span> <span class="ow">not</span> <span class="n">prelim</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">no_apr</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">no_apr</span> <span class="o">-</span> <span class="mi">1</span>

            <span class="n">any_update</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_run_orientation_phase</span><span class="p">(</span><span class="n">rule_list</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_rules_all</span><span class="p">,</span> <span class="n">only_lagged</span> <span class="o">=</span> <span class="kc">False</span><span class="p">)</span>

            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_cond_px</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">update_middle_marks</span> <span class="ow">and</span> <span class="n">any_update</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_update_middle_marks</span><span class="p">()</span>

        <span class="k">else</span><span class="p">:</span>

            <span class="n">only_lagged</span> <span class="o">=</span> <span class="kc">False</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">orient_contemp</span> <span class="o">&gt;=</span> <span class="mi">1</span> <span class="k">else</span> <span class="kc">True</span>
            <span class="n">any_update</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_run_orientation_phase</span><span class="p">(</span><span class="n">rule_list</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_rules_prelim_final</span><span class="p">,</span> <span class="n">only_lagged</span> <span class="o">=</span> <span class="n">only_lagged</span><span class="p">)</span>

            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_cond_px</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">update_middle_marks</span> <span class="ow">and</span> <span class="n">any_update</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_update_middle_marks</span><span class="p">()</span>

        <span class="c1"># Return</span>
        <span class="k">return</span> <span class="kc">True</span>


    <span class="k">def</span> <span class="nf">_run_non_ancestral_removal_phase</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Run the non-ancestral edge removal phase, this is Algorithm S3&quot;&quot;&quot;</span>

        <span class="c1"># Update of middle marks</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_update_middle_marks</span><span class="p">()</span>

        <span class="c1"># This function initializeds self._graph_full_dict, a nested dictionary representing the graph including links that are</span>
        <span class="c1"># forward in time. This will make the calculcation of na-pds-t sets easier.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_initialize_full_graph</span><span class="p">()</span>

        <span class="c1"># Iterate until convergence. Here, p_pc is the cardinality of the non-default part of the conditioning sets. The full</span>
        <span class="c1"># conditioning sets may have higher cardinality due to default conditioning on known parents</span>
        <span class="n">p_pc</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>

            <span class="c1">##########################################################################################################</span>
            <span class="c1">### Run the next removal iteration #######################################################################</span>

            <span class="c1"># Force-quit while loop when p_pc exceeds the limit put by self.max_p_global or self.max_p_non_ancestral</span>
            <span class="k">if</span> <span class="n">p_pc</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_p_global</span> <span class="ow">or</span> <span class="n">p_pc</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_p_non_ancestral</span><span class="p">:</span>
                <span class="k">break</span>

            <span class="c1"># Verbose output</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                <span class="k">if</span> <span class="n">p_pc</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">Starting test phase</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;p = </span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">p_pc</span><span class="p">))</span>

            <span class="c1"># Variables to memorize the occurence and absence of certain events in the below edge removal phase</span>
            <span class="n">has_converged</span> <span class="o">=</span> <span class="kc">True</span>
            <span class="n">any_removal</span> <span class="o">=</span> <span class="kc">False</span>

            <span class="c1"># Generate the prioritized link list</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">auto_first</span><span class="p">:</span>

                <span class="n">link_list</span> <span class="o">=</span> <span class="p">[</span><span class="n">product</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">),</span> <span class="nb">range</span><span class="p">(</span><span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">,</span> <span class="mi">0</span><span class="p">))]</span>
                <span class="n">link_list</span> <span class="o">=</span> <span class="n">link_list</span> <span class="o">+</span> <span class="p">[</span><span class="n">product</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">),</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">),</span> <span class="nb">range</span><span class="p">(</span><span class="o">-</span><span class="n">lag</span><span class="p">,</span> <span class="o">-</span><span class="n">lag</span> <span class="o">+</span> <span class="mi">1</span><span class="p">))</span> <span class="k">for</span> <span class="n">lag</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)]</span>

            <span class="k">else</span><span class="p">:</span>

                <span class="n">link_list</span> <span class="o">=</span> <span class="p">[</span><span class="n">product</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">),</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">),</span> <span class="nb">range</span><span class="p">(</span><span class="o">-</span><span class="n">lag</span><span class="p">,</span> <span class="o">-</span><span class="n">lag</span> <span class="o">+</span> <span class="mi">1</span><span class="p">))</span> <span class="k">for</span> <span class="n">lag</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)]</span>


            <span class="c1"># Run through all elements of link_list. Each element of link_list specifies ordered pairs of variables whose connecting</span>
            <span class="c1"># edges are then subjected to conditional independence tests</span>
            <span class="k">for</span> <span class="n">links</span> <span class="ow">in</span> <span class="n">link_list</span><span class="p">:</span>

                <span class="c1"># Memory variables for storing edges that are marked for removal</span>
                <span class="n">to_remove</span> <span class="o">=</span> <span class="p">{</span><span class="n">j</span><span class="p">:</span> <span class="p">{}</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)}</span>

                <span class="c1"># Iterate through all edges specified by links. Note that since the variables paris are ordered, (A, B) and (B, A) are</span>
                <span class="c1"># seen as different pairs.</span>
                <span class="k">for</span> <span class="n">pair</span> <span class="ow">in</span> <span class="n">links</span><span class="p">:</span>

                    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">pair</span><span class="p">)</span> <span class="o">==</span> <span class="mi">2</span><span class="p">:</span>
                        <span class="n">X</span> <span class="o">=</span> <span class="p">(</span><span class="n">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
                        <span class="n">Y</span> <span class="o">=</span> <span class="p">(</span><span class="n">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="mi">0</span><span class="p">)</span>
                    <span class="k">else</span><span class="p">:</span>
                        <span class="n">X</span> <span class="o">=</span> <span class="p">(</span><span class="n">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">pair</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>
                        <span class="n">Y</span> <span class="o">=</span> <span class="p">(</span><span class="n">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mi">0</span><span class="p">)</span>

                        <span class="c1"># Do not test auto-links twice</span>
                        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">auto_first</span> <span class="ow">and</span> <span class="n">X</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="n">Y</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span>
                            <span class="k">continue</span>

                    <span class="c1">######################################################################################################</span>
                    <span class="c1">### Exclusion of links ###############################################################################</span>

                    <span class="c1"># Exclude the current link if ...</span>
                    <span class="c1"># ... X = Y</span>
                    <span class="k">if</span> <span class="n">X</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">X</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="n">Y</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span>
                        <span class="k">continue</span>
                    <span class="c1"># ... X &gt; Y</span>
                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_smaller</span><span class="p">(</span><span class="n">Y</span><span class="p">,</span> <span class="n">X</span><span class="p">):</span>
                        <span class="k">continue</span>

                    <span class="c1"># Get the current link</span>
                    <span class="n">link</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">)</span>

                    <span class="c1"># Exclude the current link if ...</span>
                    <span class="k">if</span> <span class="n">link</span> <span class="o">==</span> <span class="s2">&quot;&quot;</span><span class="p">:</span>
                        <span class="k">continue</span>
                    <span class="c1"># ... the link is definitely part of G</span>
                    <span class="k">if</span> <span class="n">link</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;-&quot;</span><span class="p">:</span>
                        <span class="k">continue</span>

                    <span class="c1">######################################################################################################</span>
                    <span class="c1">### Determine which tests the link will be subjected to  #############################################</span>

                    <span class="c1"># The algorithm always searches for separating sets in na-pds-t(Y, X). Depending on whether the X and Y are</span>
                    <span class="c1"># contemporaneous on some global options, the algorithm may also search for separating sets in na-pds-t(X, Y)</span>
                    <span class="n">test_X</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="p">(</span><span class="n">X</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">or</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">max_cond_px</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_cond_px</span> <span class="o">&gt;=</span> <span class="n">p_pc</span><span class="p">))</span> <span class="k">else</span> <span class="kc">False</span>
                    
                    <span class="c1">######################################################################################################</span>
                    <span class="c1">### Preparation of default conditioning sets and PC search sets ######################################</span>

                    <span class="c1"># Verbose output</span>
                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">:</span>
                        <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;_get_na_pds_t &quot;</span><span class="p">)</span>

                    <span class="n">S_default_YX</span><span class="p">,</span> <span class="n">S_search_YX</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_default_and_search_sets</span><span class="p">(</span><span class="n">Y</span><span class="p">,</span> <span class="n">X</span><span class="p">,</span> <span class="s2">&quot;non-ancestral&quot;</span><span class="p">)</span>

                    <span class="bp">self</span><span class="o">.</span><span class="n">max_na_search_set_found</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">max_na_search_set_found</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">S_search_YX</span><span class="p">))</span>

                    <span class="k">if</span> <span class="n">test_X</span><span class="p">:</span>
                        <span class="n">S_default_XY</span><span class="p">,</span> <span class="n">S_search_XY</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_default_and_search_sets</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="s2">&quot;non-ancestral&quot;</span><span class="p">)</span>

                        <span class="bp">self</span><span class="o">.</span><span class="n">max_na_search_set_found</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">max_na_search_set_found</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">S_search_XY</span><span class="p">))</span>

                    <span class="c1"># If the search set exceeds the specified bounds, do not test this link</span>
                    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">S_search_YX</span><span class="p">)</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_pds_set</span> <span class="ow">or</span> <span class="p">(</span><span class="n">test_X</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">S_search_XY</span><span class="p">)</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_pds_set</span><span class="p">):</span>
                        <span class="k">continue</span>

                    <span class="c1">######################################################################################################</span>

                    <span class="c1">######################################################################################################</span>
                    <span class="c1">### Middle mark updates ##############################################################################</span>

                    <span class="c1"># Note: Updating the middle marks here, within the for-loop, does not spoil order independence. In fact, this</span>
                    <span class="c1"># update does not influence the flow of the for-loop at all</span>
                    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">S_search_YX</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">p_pc</span> <span class="ow">or</span> <span class="p">(</span><span class="n">test_X</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">S_search_XY</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">p_pc</span><span class="p">):</span>
                        <span class="c1"># Mark the link from X to Y as converged, remember the fixation, then continue</span>
                        <span class="bp">self</span><span class="o">.</span><span class="n">_write_link</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;-&quot;</span> <span class="o">+</span> <span class="n">link</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">verbosity</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span><span class="p">)</span>
                        <span class="k">continue</span>

                    <span class="k">else</span><span class="p">:</span>
                        <span class="n">has_converged</span> <span class="o">=</span> <span class="kc">False</span>


                    <span class="c1">######################################################################################################</span>
                    <span class="c1">### Tests for conditional independence ###############################################################</span>

                    <span class="c1"># If option self.break_once_separated is True, the below for-loops will be broken immediately once a separating set</span>
                    <span class="c1"># has been found. In conjunction with the modified majority rule employed for orienting links, order independence</span>
                    <span class="c1"># (with respect to the index &#39;i&#39; on X^i_t) then requires that the tested conditioning sets are ordered in an order</span>
                    <span class="c1"># independent way. Here, the minimal effect size of previous conditional independence tests serve as an order</span>
                    <span class="c1"># independent order criterion.</span>
                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">break_once_separated</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">np</span><span class="o">.</span><span class="n">isinf</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">max_q_global</span><span class="p">):</span>
                        <span class="n">S_search_YX</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_sort_search_set</span><span class="p">(</span><span class="n">S_search_YX</span><span class="p">,</span> <span class="n">Y</span><span class="p">)</span>
                        <span class="k">if</span> <span class="n">test_X</span><span class="p">:</span>
                            <span class="n">S_search_XY</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_sort_search_set</span><span class="p">(</span><span class="n">S_search_XY</span><span class="p">,</span> <span class="n">X</span><span class="p">)</span>

                    <span class="c1"># Verbose output</span>
                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">:</span>
                        <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;for S_pc in combinations(S_search_YX, p_pc)&quot;</span><span class="p">)</span>

                    <span class="c1"># Run through all cardinality p_pc subsets of S_search_YX</span>
                    <span class="n">q_count</span> <span class="o">=</span> <span class="mi">0</span>
                    <span class="k">for</span> <span class="n">S_pc</span> <span class="ow">in</span> <span class="n">combinations</span><span class="p">(</span><span class="n">S_search_YX</span><span class="p">,</span> <span class="n">p_pc</span><span class="p">):</span>

                        <span class="n">q_count</span> <span class="o">=</span> <span class="n">q_count</span> <span class="o">+</span> <span class="mi">1</span>
                        <span class="k">if</span> <span class="n">q_count</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_q_global</span><span class="p">:</span>
                            <span class="k">break</span>

                        <span class="c1"># Build the full conditioning set</span>
                        <span class="n">Z</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">S_pc</span><span class="p">)</span>
                        <span class="n">Z</span> <span class="o">=</span> <span class="n">Z</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="n">S_default_YX</span><span class="p">)</span>

                        <span class="c1"># Test conditional independence of X and Y given Z</span>
                        <span class="c1"># val, pval = self.cond_ind_test.run_test(X = [X], Y = [Y], Z = list(Z), tau_max = self.tau_max)</span>
                        <span class="n">val</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">dependent</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cond_ind_test</span><span class="o">.</span><span class="n">run_test</span><span class="p">(</span><span class="n">X</span> <span class="o">=</span> <span class="p">[</span><span class="n">X</span><span class="p">],</span> <span class="n">Y</span> <span class="o">=</span> <span class="p">[</span><span class="n">Y</span><span class="p">],</span> <span class="n">Z</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">Z</span><span class="p">),</span> 
                            <span class="n">tau_max</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">,</span> <span class="n">alpha_or_thres</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">pc_alpha</span><span class="p">)</span>

                        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">:</span>
                            <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Non-ANC(Y):    </span><span class="si">%s</span><span class="s2"> _|_ </span><span class="si">%s</span><span class="s2">  |  S_def = </span><span class="si">%s</span><span class="s2">, S_pc = </span><span class="si">%s</span><span class="s2">: val = </span><span class="si">%.2f</span><span class="s2"> / pval = </span><span class="si">% .4f</span><span class="s2">&quot;</span> <span class="o">%</span>
                                <span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="n">S_default_YX</span><span class="p">]),</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="n">S_pc</span><span class="p">]),</span> <span class="n">val</span><span class="p">,</span> <span class="n">pval</span><span class="p">))</span>

                        <span class="c1"># Accordingly update dictionaries that keep track of the maximal p-value and the corresponding test statistic</span>
                        <span class="c1"># values and conditioning set cardinalities</span>
                        <span class="bp">self</span><span class="o">.</span><span class="n">_update_pval_val_card_dicts</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">val</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">Z</span><span class="p">))</span>

                        <span class="c1"># Check whether test result was significant</span>
                        <span class="k">if</span> <span class="ow">not</span> <span class="n">dependent</span><span class="p">:</span> <span class="c1"># pval &gt; self.pc_alpha:</span>

                            <span class="c1"># Mark the edge from X to Y for removal and save sepset</span>
                            <span class="n">to_remove</span><span class="p">[</span><span class="n">Y</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="n">X</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span>
                            <span class="bp">self</span><span class="o">.</span><span class="n">_save_sepset</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="p">(</span><span class="nb">frozenset</span><span class="p">(</span><span class="n">Z</span><span class="p">),</span> <span class="s2">&quot;wm&quot;</span><span class="p">))</span>
        
                            <span class="c1"># Verbose output</span>
                            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;(</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) </span><span class="si">{:11}</span><span class="s2"> </span><span class="si">{}</span><span class="s2"> given </span><span class="si">{}</span><span class="s2"> union </span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">X</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">X</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s2">&quot;independent&quot;</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">S_pc</span><span class="p">,</span> <span class="n">S_default_YX</span><span class="p">))</span>

                            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">break_once_separated</span><span class="p">:</span>
                                <span class="k">break</span>

                    <span class="k">if</span> <span class="n">test_X</span><span class="p">:</span>

                        <span class="c1"># Verbose output</span>
                        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">:</span>
                            <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;for S_pc in combinations(S_search_XY, p_pc)&quot;</span><span class="p">)</span>

                        <span class="c1"># Run through all cardinality p_pc subsets of S_search_XY</span>
                        <span class="n">q_count</span> <span class="o">=</span> <span class="mi">0</span>
                        <span class="k">for</span> <span class="n">S_pc</span> <span class="ow">in</span> <span class="n">combinations</span><span class="p">(</span><span class="n">S_search_XY</span><span class="p">,</span> <span class="n">p_pc</span><span class="p">):</span>

                            <span class="n">q_count</span> <span class="o">=</span> <span class="n">q_count</span> <span class="o">+</span> <span class="mi">1</span>
                            <span class="k">if</span> <span class="n">q_count</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_q_global</span><span class="p">:</span>
                                <span class="k">break</span>

                            <span class="c1"># Build the full conditioning set</span>
                            <span class="n">Z</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">S_pc</span><span class="p">)</span>
                            <span class="n">Z</span> <span class="o">=</span> <span class="n">Z</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="n">S_default_XY</span><span class="p">)</span>

                            <span class="c1"># Test conditional independence of X and Y given Z</span>
                            <span class="c1"># val, pval = self.cond_ind_test.run_test(X = [X], Y = [Y], Z = list(Z), tau_max = self.tau_max)</span>
                            <span class="n">val</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">dependent</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cond_ind_test</span><span class="o">.</span><span class="n">run_test</span><span class="p">(</span><span class="n">X</span> <span class="o">=</span> <span class="p">[</span><span class="n">X</span><span class="p">],</span> <span class="n">Y</span> <span class="o">=</span> <span class="p">[</span><span class="n">Y</span><span class="p">],</span> <span class="n">Z</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">Z</span><span class="p">),</span> 
                                <span class="n">tau_max</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">,</span> <span class="n">alpha_or_thres</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">pc_alpha</span><span class="p">)</span>

                            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">:</span>
                                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Non-ANC(X):    </span><span class="si">%s</span><span class="s2"> _|_ </span><span class="si">%s</span><span class="s2">  |  S_def = </span><span class="si">%s</span><span class="s2">, S_pc = </span><span class="si">%s</span><span class="s2">: val = </span><span class="si">%.2f</span><span class="s2"> / pval = </span><span class="si">% .4f</span><span class="s2">&quot;</span> <span class="o">%</span>
                                    <span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="n">S_default_XY</span><span class="p">]),</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="n">S_pc</span><span class="p">]),</span> <span class="n">val</span><span class="p">,</span> <span class="n">pval</span><span class="p">))</span>

                            <span class="c1"># Accordingly update dictionaries that keep track of the maximal p-value and the corresponding test statistic</span>
                            <span class="c1"># values and conditioning set cardinalities</span>
                            <span class="bp">self</span><span class="o">.</span><span class="n">_update_pval_val_card_dicts</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">val</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">Z</span><span class="p">))</span>

                            <span class="c1"># Check whether test result was significant</span>
                            <span class="k">if</span> <span class="ow">not</span> <span class="n">dependent</span><span class="p">:</span> <span class="c1"># pval &gt; self.pc_alpha:</span>

                                <span class="c1"># Mark the edge from X to Y for removal and save sepset</span>
                                <span class="n">to_remove</span><span class="p">[</span><span class="n">Y</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="n">X</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span>
                                <span class="bp">self</span><span class="o">.</span><span class="n">_save_sepset</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="p">(</span><span class="nb">frozenset</span><span class="p">(</span><span class="n">Z</span><span class="p">),</span> <span class="s2">&quot;wm&quot;</span><span class="p">))</span>
            
                                <span class="c1"># Verbose output</span>
                                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                                    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;(</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) </span><span class="si">{:11}</span><span class="s2"> </span><span class="si">{}</span><span class="s2"> given </span><span class="si">{}</span><span class="s2"> union </span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">X</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">X</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s2">&quot;independent&quot;</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">S_pc</span><span class="p">,</span> <span class="n">S_default_YX</span><span class="p">))</span>

                                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">break_once_separated</span><span class="p">:</span>
                                    <span class="k">break</span>

                <span class="c1"># end for links in link_list</span>

                <span class="c1">##########################################################################################################</span>
                <span class="c1">### Remove edges marked for removal in to_remove #########################################################</span>

                <span class="c1"># Check whether there is any removal at all</span>
                <span class="n">any_removal_this</span> <span class="o">=</span> <span class="kc">False</span>

                <span class="c1"># Run through all of the nested dictionary</span>
                <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">):</span>
                    <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">in</span> <span class="n">to_remove</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span>

                        <span class="c1"># Remember that at least one edge has been removed, remove the edge</span>
                        <span class="n">any_removal</span> <span class="o">=</span> <span class="kc">True</span>
                        <span class="n">any_removal_this</span> <span class="o">=</span> <span class="kc">True</span>
                        <span class="bp">self</span><span class="o">.</span><span class="n">_write_link</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">verbosity</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span><span class="p">)</span>

                <span class="c1"># If any_removal_this = True, we need to recalculate full graph dict</span>
                <span class="k">if</span> <span class="n">any_removal_this</span><span class="p">:</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_initialize_full_graph</span><span class="p">()</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_na_pds_t</span> <span class="o">=</span> <span class="p">{(</span><span class="n">j</span><span class="p">,</span> <span class="o">-</span><span class="n">tau_j</span><span class="p">):</span> <span class="p">{}</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)</span> <span class="k">for</span> <span class="n">tau_j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)}</span>


            <span class="c1"># end for links in link_list</span>

            <span class="c1"># Verbose output</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">Test phase complete&quot;</span><span class="p">)</span>

            <span class="c1">##############################################################################################################</span>
            <span class="c1">### Orientations and next step ###############################################################################</span>

            <span class="k">if</span> <span class="n">any_removal</span><span class="p">:</span>
                <span class="c1"># At least one edge was removed or at least one middle mark has been updated. Therefore: i) apply the full set of</span>
                <span class="c1"># orientation rules, ii) restart the while loop at p_pc = 0, unless all edges have converged, then break the while loop</span>

                <span class="n">any_update</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_run_orientation_phase</span><span class="p">(</span><span class="n">rule_list</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_rules_all</span><span class="p">,</span> <span class="n">only_lagged</span> <span class="o">=</span> <span class="kc">False</span><span class="p">)</span>

                <span class="k">if</span> <span class="n">any_update</span><span class="p">:</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_initialize_full_graph</span><span class="p">()</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_na_pds_t</span> <span class="o">=</span> <span class="p">{(</span><span class="n">j</span><span class="p">,</span> <span class="o">-</span><span class="n">tau_j</span><span class="p">):</span> <span class="p">{}</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)</span> <span class="k">for</span> <span class="n">tau_j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)}</span>
                    <span class="n">p_pc</span> <span class="o">=</span> <span class="mi">0</span>

                <span class="k">else</span><span class="p">:</span>
                    <span class="n">p_pc</span> <span class="o">=</span> <span class="n">p_pc</span> <span class="o">+</span> <span class="mi">1</span>

            <span class="k">else</span><span class="p">:</span>
                <span class="c1"># The graph has not changed at all in this iteration of the while loop. Therefore, if all edges have converged, break</span>
                <span class="c1"># the while loop. If at least one edge has not yet converged, increase p_pc by one.</span>

                <span class="k">if</span> <span class="n">has_converged</span><span class="p">:</span>
                    <span class="k">break</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="n">p_pc</span> <span class="o">=</span> <span class="n">p_pc</span> <span class="o">+</span> <span class="mi">1</span>

        <span class="c1"># end while True</span>

        <span class="c1">##################################################################################################################</span>
        <span class="c1">### Final rule applications ######################################################################################</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">_run_orientation_phase</span><span class="p">(</span><span class="n">rule_list</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_rules_all</span><span class="p">,</span> <span class="n">only_lagged</span> <span class="o">=</span> <span class="kc">False</span><span class="p">)</span>

        <span class="c1"># Return</span>
        <span class="k">return</span> <span class="kc">True</span>


    <span class="k">def</span> <span class="nf">_run_orientation_phase</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">rule_list</span><span class="p">,</span> <span class="n">only_lagged</span> <span class="o">=</span> <span class="kc">False</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Exhaustively apply the rules specified by rule_list, this is Algorithm S4&quot;&quot;&quot;</span>

        <span class="c1"># Verbose output</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
            <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">Starting orientation phase&quot;</span><span class="p">)</span>
            <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;with rule list: &quot;</span><span class="p">,</span> <span class="n">rule_list</span><span class="p">)</span>

        <span class="c1"># Remember whether this call to _run_orientation_phase has made any update to G</span>
        <span class="n">restarted_once</span> <span class="o">=</span> <span class="kc">False</span>

        <span class="c1"># Run through all priority levels of rule_list</span>
        <span class="n">idx</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="k">while</span> <span class="n">idx</span> <span class="o">&lt;=</span> <span class="nb">len</span><span class="p">(</span><span class="n">rule_list</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">:</span>

            <span class="c1"># Some rule require self._graph_full_dict. Therefore, it is initialized once the while loop (re)-starts at the first</span>
            <span class="c1"># prioprity level</span>
            <span class="k">if</span> <span class="n">idx</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_initialize_full_graph</span><span class="p">()</span>

            <span class="c1"># Remember whether G will be updated with new useful information (&#39;x&#39; marks are considered not useful)</span>
            <span class="n">restart</span> <span class="o">=</span> <span class="kc">False</span>

            <span class="c1">###########################################################################################################</span>
            <span class="c1">### Rule application ######################################################################################</span>

            <span class="c1"># Get the current rules</span>
            <span class="n">current_rules</span> <span class="o">=</span> <span class="n">rule_list</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span>

            <span class="c1"># Prepare a list to remember marked orientations</span>
            <span class="n">to_orient</span> <span class="o">=</span> <span class="p">[]</span>

            <span class="c1"># Run through all current rules</span>
            <span class="k">for</span> <span class="n">rule</span> <span class="ow">in</span> <span class="n">current_rules</span><span class="p">:</span>

                <span class="c1"># Verbose output</span>
                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="si">{}</span><span class="s2">:&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">rule</span><span class="p">))</span>

                <span class="c1"># Exhaustively apply the rule to the graph...</span>
                <span class="n">orientations</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_apply_rule</span><span class="p">(</span><span class="n">rule</span><span class="p">,</span> <span class="n">only_lagged</span><span class="p">)</span>

                <span class="c1"># Verbose output</span>
                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                    <span class="k">for</span> <span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="n">new_link</span><span class="p">)</span> <span class="ow">in</span> <span class="nb">set</span><span class="p">(</span><span class="n">orientations</span><span class="p">):</span>
                        <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">{:10}</span><span class="s2"> (</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) </span><span class="si">{:3}</span><span class="s2"> (</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) ==&gt; (</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) </span><span class="si">{:3}</span><span class="s2"> (</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) &quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s2">&quot;Marked:&quot;</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)),</span> <span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">,</span> <span class="n">new_link</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
                    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">orientations</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                        <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Found nothing&quot;</span><span class="p">)</span>

                <span class="c1"># ... and stage the results for orientation and removal</span>
                <span class="n">to_orient</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">orientations</span><span class="p">)</span>

            <span class="c1">###########################################################################################################</span>
            <span class="c1">### Aggregation of marked orientations ####################################################################</span>

            <span class="n">links_to_remove</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
            <span class="n">links_to_fix</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
            <span class="n">new_ancs</span> <span class="o">=</span> <span class="p">{</span><span class="n">j</span><span class="p">:</span> <span class="nb">set</span><span class="p">()</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)}</span>
            <span class="n">new_non_ancs</span> <span class="o">=</span> <span class="p">{</span><span class="n">j</span><span class="p">:</span> <span class="nb">set</span><span class="p">()</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)}</span>

            <span class="c1"># Run through all of the nested dictionary</span>
            <span class="k">for</span> <span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="n">new_link</span><span class="p">)</span> <span class="ow">in</span> <span class="n">to_orient</span><span class="p">:</span>

                <span class="c1"># The old link</span>
                <span class="n">old_link</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>

                <span class="c1"># Is the link marked for removal?</span>
                <span class="k">if</span> <span class="n">new_link</span> <span class="o">==</span> <span class="s2">&quot;&quot;</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">old_link</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
                    <span class="n">links_to_remove</span><span class="o">.</span><span class="n">add</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">))</span>
                    <span class="k">continue</span>

                <span class="c1"># Assert that no preceeding variable is marked as an ancestor of later variable</span>
                <span class="k">assert</span> <span class="ow">not</span> <span class="p">(</span><span class="n">lag_i</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">new_link</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;-&quot;</span><span class="p">)</span>

                <span class="c1"># Is the link marked for fixation?</span>
                <span class="k">if</span> <span class="n">new_link</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;-&quot;</span> <span class="ow">and</span> <span class="n">old_link</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;-&quot;</span><span class="p">:</span>
                    <span class="n">links_to_fix</span><span class="o">.</span><span class="n">add</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">))</span>

                <span class="c1"># New ancestral relation of (i, lag_i) to (j, 0)</span>
                <span class="k">if</span> <span class="n">new_link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;-&quot;</span> <span class="ow">and</span> <span class="n">old_link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;-&quot;</span><span class="p">:</span>
                    <span class="n">new_ancs</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">add</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">))</span>
                <span class="k">elif</span> <span class="n">new_link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;&lt;&quot;</span> <span class="ow">and</span> <span class="n">old_link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;&lt;&quot;</span><span class="p">:</span>
                    <span class="n">new_non_ancs</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">add</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">))</span>
                
                <span class="c1"># New ancestral relation of (j, 0) to (i, lag_i == 0)</span>
                <span class="k">if</span> <span class="n">lag_i</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                    <span class="k">if</span> <span class="n">new_link</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;-&quot;</span> <span class="ow">and</span> <span class="n">old_link</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;-&quot;</span><span class="p">:</span>
                        <span class="n">new_ancs</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">add</span><span class="p">((</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
                    <span class="k">elif</span> <span class="n">new_link</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;&gt;&quot;</span> <span class="ow">and</span> <span class="n">old_link</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;&gt;&quot;</span><span class="p">:</span>
                        <span class="n">new_non_ancs</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">add</span><span class="p">((</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>

            <span class="c1"># Resolve conflicts about removal and fixation</span>
            <span class="n">ambiguous_links</span> <span class="o">=</span> <span class="n">links_to_fix</span><span class="o">.</span><span class="n">intersection</span><span class="p">(</span><span class="n">links_to_remove</span><span class="p">)</span>
            <span class="n">links_to_fix</span> <span class="o">=</span> <span class="n">links_to_fix</span><span class="o">.</span><span class="n">difference</span><span class="p">(</span><span class="n">ambiguous_links</span><span class="p">)</span>
            <span class="n">links_to_remove</span> <span class="o">=</span> <span class="n">links_to_remove</span><span class="o">.</span><span class="n">difference</span><span class="p">(</span><span class="n">ambiguous_links</span><span class="p">)</span>

            <span class="c1">###########################################################################################################</span>
            <span class="c1">### Removals, update middle marks, update ancestral information ###########################################</span>

            <span class="c1"># Remove links</span>
            <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">in</span> <span class="n">links_to_remove</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_write_link</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">verbosity</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span><span class="p">)</span>
                <span class="n">restart</span> <span class="o">=</span> <span class="kc">True</span>

            <span class="c1"># Fix links</span>
            <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">in</span> <span class="n">links_to_fix</span><span class="p">:</span>
                <span class="n">old_link</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
                <span class="n">new_link</span> <span class="o">=</span> <span class="n">old_link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;-&quot;</span> <span class="o">+</span> <span class="n">old_link</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_write_link</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">new_link</span><span class="p">,</span> <span class="n">verbosity</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span><span class="p">)</span>
                <span class="n">restart</span> <span class="o">=</span> <span class="kc">True</span>

            <span class="c1"># Mark links as ambiguous</span>
            <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">in</span> <span class="n">ambiguous_links</span><span class="p">:</span>
                <span class="n">old_link</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
                <span class="n">new_link</span> <span class="o">=</span> <span class="n">old_link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;x&quot;</span> <span class="o">+</span> <span class="n">old_link</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_write_link</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">new_link</span><span class="p">,</span> <span class="n">verbosity</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span><span class="p">)</span>

            <span class="c1"># Update ancestral information. The function called includes conflict resolution</span>
            <span class="n">restart</span> <span class="o">=</span> <span class="n">restart</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_apply_new_ancestral_information</span><span class="p">(</span><span class="n">new_non_ancs</span><span class="p">,</span> <span class="n">new_ancs</span><span class="p">)</span>

            <span class="c1">###########################################################################################################</span>
            <span class="c1">### Make separating sets of removed links weakly minimal ##################################################</span>

            <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">links_to_remove</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>

                <span class="c1"># Verbose output</span>
                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">Links were removed by rules</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span>

                <span class="n">new_ancs</span> <span class="o">=</span> <span class="p">{</span><span class="n">j</span><span class="p">:</span> <span class="nb">set</span><span class="p">()</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)}</span>
                <span class="n">new_non_ancs</span> <span class="o">=</span> <span class="p">{</span><span class="n">j</span><span class="p">:</span> <span class="nb">set</span><span class="p">()</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)}</span>

                <span class="c1"># Run through all links that have been removed</span>
                <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">in</span> <span class="n">links_to_remove</span><span class="p">:</span>

                    <span class="n">X</span> <span class="o">=</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span>
                    <span class="n">Y</span> <span class="o">=</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>

                    <span class="c1"># Get ancestors of X and Y</span>
                    <span class="n">ancs_XY</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_ancs</span><span class="p">([</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">])</span><span class="o">.</span><span class="n">difference</span><span class="p">({</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">})</span>

                    <span class="c1"># Read out all separating sets that were found in the rule phase, then consider only those of minimal</span>
                    <span class="c1"># cardinality</span>
                    <span class="n">old_sepsets_all</span> <span class="o">=</span> <span class="p">{</span><span class="n">Z</span> <span class="k">for</span> <span class="p">(</span><span class="n">Z</span><span class="p">,</span> <span class="n">_</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_sepsets</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">)}</span>
                    <span class="n">min_size</span> <span class="o">=</span> <span class="nb">min</span><span class="p">({</span><span class="nb">len</span><span class="p">(</span><span class="n">Z</span><span class="p">)</span> <span class="k">for</span> <span class="n">Z</span> <span class="ow">in</span> <span class="n">old_sepsets_all</span><span class="p">})</span>
                    <span class="n">old_sepsets_smallest</span> <span class="o">=</span> <span class="p">{</span><span class="n">Z</span> <span class="k">for</span> <span class="n">Z</span> <span class="ow">in</span> <span class="n">old_sepsets_all</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">Z</span><span class="p">)</span> <span class="o">==</span> <span class="n">min_size</span><span class="p">}</span>

                    <span class="c1"># For all separating sets of minimal cardinality, find weakly minimal separating subsets</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_delete_sepsets</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">)</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_make_sepset_weakly_minimal</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">old_sepsets_smallest</span><span class="p">,</span> <span class="n">ancs_XY</span><span class="p">)</span>
                    <span class="n">new_sepsets</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_sepsets</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">)</span>

                <span class="c1"># end for (i, j, lag_i) in links_to_remove</span>
            <span class="c1"># end  if len(links_to_remove) &gt; 0</span>

            <span class="c1"># If any useful new information was found, go back to idx = 0, else increase idx by 1</span>
            <span class="k">if</span> <span class="n">restart</span><span class="p">:</span>
                <span class="n">idx</span> <span class="o">=</span> <span class="mi">0</span>
                <span class="n">restarted_once</span> <span class="o">=</span> <span class="kc">True</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">idx</span> <span class="o">=</span> <span class="n">idx</span> <span class="o">+</span> <span class="mi">1</span>

        <span class="c1"># end while idx &lt;= len(rule_list) - 1</span>

        <span class="c1"># Verbose output</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
            <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">Orientation phase complete&quot;</span><span class="p">)</span>

        <span class="c1"># No return value</span>
        <span class="k">return</span> <span class="n">restarted_once</span>

    <span class="c1">########################################################################################################################</span>
    <span class="c1">########################################################################################################################</span>
    <span class="c1">########################################################################################################################</span>

    <span class="k">def</span> <span class="nf">_get_default_and_search_sets</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">phase</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return the default conditioning set and PC search set&quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="n">phase</span> <span class="o">==</span> <span class="s2">&quot;ancestral&quot;</span><span class="p">:</span>

            <span class="c1"># This is a-pds-t(A, B)</span>
            <span class="n">S_raw</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_a_pds_t</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">)</span>

            <span class="c1"># Determine the default conditioning set</span>
            <span class="n">S_default</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_parents</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">)</span><span class="o">.</span><span class="n">difference</span><span class="p">({</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">})</span>

            <span class="c1"># Determine the PC search set</span>
            <span class="n">S_search</span> <span class="o">=</span> <span class="n">S_raw</span><span class="o">.</span><span class="n">difference</span><span class="p">(</span><span class="n">S_default</span><span class="p">)</span>


        <span class="k">elif</span> <span class="n">phase</span> <span class="o">==</span> <span class="s2">&quot;non-ancestral&quot;</span><span class="p">:</span>

            <span class="c1"># This is na-pds-t(A, B)</span>
            <span class="n">S_raw</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_na_pds_t</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">)</span>

            <span class="bp">self</span><span class="o">.</span><span class="n">max_na_pds_set_found</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">max_na_pds_set_found</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">S_raw</span><span class="p">))</span>

            <span class="c1"># Determine the default conditioning set</span>
            <span class="n">S_default</span> <span class="o">=</span> <span class="n">S_raw</span><span class="o">.</span><span class="n">intersection</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_get_ancs</span><span class="p">([</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">]))</span>
            <span class="n">S_default</span> <span class="o">=</span> <span class="n">S_default</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_get_parents</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">))</span>
            <span class="n">S_default</span> <span class="o">=</span> <span class="n">S_default</span><span class="o">.</span><span class="n">difference</span><span class="p">({</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">})</span>

            <span class="c1"># Determine the PC search set</span>
            <span class="n">S_search</span> <span class="o">=</span> <span class="n">S_raw</span><span class="o">.</span><span class="n">difference</span><span class="p">(</span><span class="n">S_default</span><span class="p">)</span>

        <span class="c1"># Return</span>
        <span class="k">return</span> <span class="n">S_default</span><span class="p">,</span> <span class="n">S_search</span>


    <span class="k">def</span> <span class="nf">_apply_new_ancestral_information</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">new_non_ancs</span><span class="p">,</span> <span class="n">new_ancs</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Apply the new ancestorships and non-ancestorships specified by new_non_ancs and new_ancs to the current graph. Conflicts</span>
<span class="sd">        are resolved by marking. Returns True if any circle mark was turned into a head or tail, else False.&quot;&quot;&quot;</span>

        <span class="c1">#######################################################################################################</span>
        <span class="c1">### Preprocessing #####################################################################################</span>

        <span class="c1"># Memory variables</span>
        <span class="n">add_to_def_non_ancs</span> <span class="o">=</span> <span class="p">{</span><span class="n">j</span><span class="p">:</span> <span class="nb">set</span><span class="p">()</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)}</span>
        <span class="n">add_to_def_ancs</span> <span class="o">=</span> <span class="p">{</span><span class="n">j</span><span class="p">:</span> <span class="nb">set</span><span class="p">()</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)}</span>
        <span class="n">add_to_ambiguous_ancestorships</span> <span class="o">=</span> <span class="p">{</span><span class="n">j</span><span class="p">:</span> <span class="nb">set</span><span class="p">()</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)}</span>
        <span class="n">put_head_or_tail</span> <span class="o">=</span> <span class="kc">False</span>

        <span class="c1"># Default values</span>
        <span class="k">if</span> <span class="n">new_non_ancs</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
            <span class="n">new_non_ancs</span> <span class="o">=</span> <span class="p">{</span><span class="n">j</span><span class="p">:</span> <span class="nb">set</span><span class="p">()</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)}</span>

        <span class="k">if</span> <span class="n">new_ancs</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
            <span class="n">new_ancs</span> <span class="o">=</span> <span class="p">{</span><span class="n">j</span><span class="p">:</span> <span class="nb">set</span><span class="p">()</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)}</span>

        <span class="c1"># Marking A as ancestor of B implies that B is marked as a non-ancestor of A. This is only non-trivial for A before B</span>
        <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">):</span>
            <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">in</span> <span class="n">new_ancs</span><span class="p">[</span><span class="n">j</span><span class="p">]:</span>
                <span class="k">if</span> <span class="n">lag_i</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                    <span class="n">new_non_ancs</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">add</span><span class="p">((</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>

        <span class="c1">#######################################################################################################</span>
        <span class="c1">### Conflict resolution ###############################################################################</span>

        <span class="c1"># Iterate through new_non_ancs</span>
        <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">):</span>
            <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">in</span> <span class="n">new_non_ancs</span><span class="p">[</span><span class="n">j</span><span class="p">]:</span>
                <span class="c1"># X = (i, lag_i), Y = (j, 0)</span>
                <span class="c1"># X is marked as non-ancestor for Y</span>

                <span class="c1"># Conflict resolution</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">ambiguous_ancestorships</span><span class="p">[</span><span class="n">j</span><span class="p">]:</span>
                    <span class="c1"># There is a conflict, since it is already marked as ambiguous whether X is an ancestor of Y</span>
                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                        <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">{:10}</span><span class="s2"> (</span><span class="si">{}</span><span class="s2">, </span><span class="si">{:2}</span><span class="s2">) marked as non-anc of </span><span class="si">{}</span><span class="s2"> but saved as ambiguous&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s2">&quot;Conflict:&quot;</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">,</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>

                <span class="k">elif</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">def_ancs</span><span class="p">[</span><span class="n">j</span><span class="p">]:</span>
                    <span class="c1"># There is a conflict, since X is already marked as ancestor of Y</span>
                    <span class="n">add_to_ambiguous_ancestorships</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">add</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">))</span>

                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                        <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">{:10}</span><span class="s2"> (</span><span class="si">{}</span><span class="s2">, </span><span class="si">{:2}</span><span class="s2">) marked as non-anc of </span><span class="si">{}</span><span class="s2"> but saved as anc&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s2">&quot;Conflict:&quot;</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">,</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>

                <span class="k">elif</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">in</span> <span class="n">new_ancs</span><span class="p">[</span><span class="n">j</span><span class="p">]:</span>
                    <span class="c1"># There is a conflict, since X is also marked as a new ancestor of Y</span>
                    <span class="n">add_to_ambiguous_ancestorships</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">add</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">))</span>

                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                        <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">{:10}</span><span class="s2"> (</span><span class="si">{}</span><span class="s2">, </span><span class="si">{:2}</span><span class="s2">) marked as both anc- and non-anc of </span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s2">&quot;Conflict:&quot;</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">,</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>

                <span class="k">else</span><span class="p">:</span>
                    <span class="c1"># There is no conflict</span>
                    <span class="n">add_to_def_non_ancs</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">add</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">))</span>
                    
        <span class="c1"># Iterate through new_ancs</span>
        <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">):</span>
            <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">in</span> <span class="n">new_ancs</span><span class="p">[</span><span class="n">j</span><span class="p">]:</span>
                <span class="c1"># X = (i, lag_i), Y = (j, 0)</span>
                <span class="c1"># X is marked as ancestor for Y</span>

                <span class="c1"># Conflict resolution</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">ambiguous_ancestorships</span><span class="p">[</span><span class="n">j</span><span class="p">]:</span>
                    <span class="c1"># There is a conflict, since it is already marked as ambiguous whether X is an ancestor of Y</span>
                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                        <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">{:10}</span><span class="s2"> (</span><span class="si">{}</span><span class="s2">, </span><span class="si">{:2}</span><span class="s2">) marked as anc of </span><span class="si">{}</span><span class="s2"> but saved as ambiguous&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s2">&quot;Conflict:&quot;</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">,</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>

                <span class="k">elif</span> <span class="n">lag_i</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">ambiguous_ancestorships</span><span class="p">[</span><span class="n">i</span><span class="p">]:</span>
                    <span class="c1"># There is a conflict, since X and Y are contemporaneous and it is already marked ambiguous as whether Y is an</span>
                    <span class="c1"># ancestor of X</span>
                    <span class="c1"># Note: This is required here, because X being an ancestor of Y implies that Y is not an ancestor of X. This</span>
                    <span class="c1"># ambiguity cannot exist when X is before Y</span>
                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                        <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">{:10}</span><span class="s2"> (</span><span class="si">{}</span><span class="s2">, </span><span class="si">{:2}</span><span class="s2">) marked as anc of </span><span class="si">{}</span><span class="s2"> but saved as ambiguous&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s2">&quot;Conflict:&quot;</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">,</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>

                <span class="k">elif</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">def_non_ancs</span><span class="p">[</span><span class="n">j</span><span class="p">]:</span>
                    <span class="c1"># There is a conflict, since X is already marked as non-ancestor of Y</span>
                    <span class="n">add_to_ambiguous_ancestorships</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">add</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">))</span>

                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                        <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">{:10}</span><span class="s2"> (</span><span class="si">{}</span><span class="s2">, </span><span class="si">{:2}</span><span class="s2">) marked as anc of </span><span class="si">{}</span><span class="s2"> but saved as non-anc&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s2">&quot;Conflict:&quot;</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">,</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>

                <span class="k">elif</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">in</span> <span class="n">new_non_ancs</span><span class="p">[</span><span class="n">j</span><span class="p">]:</span>
                    <span class="c1"># There is a conflict, since X is also marked as a new non-ancestor of Y</span>
                    <span class="n">add_to_ambiguous_ancestorships</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">add</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">))</span>

                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                        <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">{:10}</span><span class="s2"> (</span><span class="si">{}</span><span class="s2">, </span><span class="si">{:2}</span><span class="s2">) marked as both anc- and non-anc of </span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s2">&quot;Conflict:&quot;</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">,</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>

                <span class="k">else</span><span class="p">:</span>
                    <span class="c1"># There is no conflict</span>
                    <span class="n">add_to_def_ancs</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">add</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">))</span>

        <span class="c1">#######################################################################################################</span>

        <span class="c1">#######################################################################################################</span>
        <span class="c1">### Apply the ambiguous information ###################################################################</span>

        <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">):</span>

            <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">in</span> <span class="n">add_to_ambiguous_ancestorships</span><span class="p">[</span><span class="n">j</span><span class="p">]:</span>

                <span class="n">old_link</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
                <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">old_link</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">old_link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;x&quot;</span><span class="p">:</span>

                    <span class="n">new_link</span> <span class="o">=</span> <span class="s2">&quot;x&quot;</span> <span class="o">+</span> <span class="n">old_link</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">old_link</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_write_link</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">new_link</span><span class="p">,</span> <span class="n">verbosity</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span><span class="p">)</span>

                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">def_ancs</span><span class="p">[</span><span class="n">j</span><span class="p">]:</span>
                        <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">{:10}</span><span class="s2"> Removing (</span><span class="si">{}</span><span class="s2">, </span><span class="si">{:2}</span><span class="s2">) as anc of </span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s2">&quot;Update:&quot;</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">,</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">def_non_ancs</span><span class="p">[</span><span class="n">j</span><span class="p">]:</span>
                        <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">{:10}</span><span class="s2"> Removing (</span><span class="si">{}</span><span class="s2">, </span><span class="si">{:2}</span><span class="s2">) as non-anc of </span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s2">&quot;Update:&quot;</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">,</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>

                <span class="bp">self</span><span class="o">.</span><span class="n">def_ancs</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">discard</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">))</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">def_non_ancs</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">discard</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">))</span>

                <span class="k">if</span> <span class="n">lag_i</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>

                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span> <span class="ow">and</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">def_ancs</span><span class="p">[</span><span class="n">i</span><span class="p">]:</span>
                        <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">{:10}</span><span class="s2"> Removing </span><span class="si">{}</span><span class="s2"> as anc of </span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s2">&quot;Update:&quot;</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">,</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>

                    <span class="bp">self</span><span class="o">.</span><span class="n">def_ancs</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">discard</span><span class="p">((</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
                    <span class="c1"># Do we also need the following?</span>
                    <span class="c1"># self.def_non_ancs[i].discard((j, 0))</span>

                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span> <span class="ow">and</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">ambiguous_ancestorships</span><span class="p">[</span><span class="n">j</span><span class="p">]:</span>
                    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">{:10}</span><span class="s2"> Marking ancestorship of (</span><span class="si">{}</span><span class="s2">, </span><span class="si">{:2}</span><span class="s2">) to </span><span class="si">{}</span><span class="s2"> as ambiguous&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s2">&quot;Update:&quot;</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">,</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>

                <span class="bp">self</span><span class="o">.</span><span class="n">ambiguous_ancestorships</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">add</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">))</span>

        <span class="c1">#######################################################################################################</span>
        <span class="c1">### Apply the unambiguous information #################################################################</span>

        <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">):</span>

            <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">in</span> <span class="n">add_to_def_non_ancs</span><span class="p">[</span><span class="n">j</span><span class="p">]:</span>

                <span class="n">old_link</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
                <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">old_link</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">old_link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;&lt;&quot;</span><span class="p">:</span>
                    <span class="n">new_link</span> <span class="o">=</span> <span class="s2">&quot;&lt;&quot;</span> <span class="o">+</span> <span class="n">old_link</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">old_link</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_write_link</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">new_link</span><span class="p">,</span> <span class="n">verbosity</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span><span class="p">)</span>
                    <span class="n">put_head_or_tail</span> <span class="o">=</span> <span class="kc">True</span>

                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span> <span class="ow">and</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">def_non_ancs</span><span class="p">[</span><span class="n">j</span><span class="p">]:</span>
                    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">{:10}</span><span class="s2"> Marking (</span><span class="si">{}</span><span class="s2">, </span><span class="si">{:2}</span><span class="s2">) as non-anc of </span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s2">&quot;Update:&quot;</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">,</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>  

                <span class="bp">self</span><span class="o">.</span><span class="n">def_non_ancs</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">add</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">))</span>


            <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">in</span> <span class="n">add_to_def_ancs</span><span class="p">[</span><span class="n">j</span><span class="p">]:</span>

                <span class="n">old_link</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
                <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">old_link</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="p">(</span><span class="n">old_link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;-&quot;</span> <span class="ow">or</span> <span class="n">old_link</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;&gt;&quot;</span><span class="p">):</span>
                    <span class="n">new_link</span> <span class="o">=</span> <span class="s2">&quot;-&quot;</span> <span class="o">+</span> <span class="n">old_link</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;&gt;&quot;</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_write_link</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">new_link</span><span class="p">,</span> <span class="n">verbosity</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span><span class="p">)</span>
                    <span class="n">put_head_or_tail</span> <span class="o">=</span> <span class="kc">True</span>

                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span> <span class="ow">and</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">def_ancs</span><span class="p">[</span><span class="n">j</span><span class="p">]:</span>
                    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">{:10}</span><span class="s2"> Marking (</span><span class="si">{}</span><span class="s2">, </span><span class="si">{:2}</span><span class="s2">) as anc of </span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s2">&quot;Update:&quot;</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">,</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>

                <span class="bp">self</span><span class="o">.</span><span class="n">def_ancs</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">add</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">))</span>

                <span class="k">if</span> <span class="n">lag_i</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>

                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span> <span class="ow">and</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">def_non_ancs</span><span class="p">[</span><span class="n">i</span><span class="p">]:</span>
                        <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">{:10}</span><span class="s2"> Marking </span><span class="si">{}</span><span class="s2"> as non-anc of </span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s2">&quot;Update:&quot;</span><span class="p">,(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>

                    <span class="bp">self</span><span class="o">.</span><span class="n">def_non_ancs</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">add</span><span class="p">((</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>

        <span class="c1">#######################################################################################################</span>

        <span class="k">return</span> <span class="n">put_head_or_tail</span>

    <span class="k">def</span> <span class="nf">_apply_rule</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">rule</span><span class="p">,</span> <span class="n">only_lagged</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Call the orientation-removal-rule specified by the string argument rule.&quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="n">rule</span> <span class="o">==</span> <span class="s2">&quot;APR&quot;</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_apply_APR</span><span class="p">(</span><span class="n">only_lagged</span><span class="p">)</span>
        <span class="k">elif</span> <span class="n">rule</span> <span class="o">==</span> <span class="s2">&quot;ER-00-a&quot;</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_apply_ER00a</span><span class="p">(</span><span class="n">only_lagged</span><span class="p">)</span>
        <span class="k">elif</span> <span class="n">rule</span> <span class="o">==</span> <span class="s2">&quot;ER-00-b&quot;</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_apply_ER00b</span><span class="p">(</span><span class="n">only_lagged</span><span class="p">)</span>
        <span class="k">elif</span> <span class="n">rule</span> <span class="o">==</span> <span class="s2">&quot;ER-00-c&quot;</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_apply_ER00c</span><span class="p">(</span><span class="n">only_lagged</span><span class="p">)</span>
        <span class="k">elif</span> <span class="n">rule</span> <span class="o">==</span> <span class="s2">&quot;ER-00-d&quot;</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_apply_ER00d</span><span class="p">(</span><span class="n">only_lagged</span><span class="p">)</span>
        <span class="k">elif</span> <span class="n">rule</span> <span class="o">==</span> <span class="s2">&quot;ER-01&quot;</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_apply_ER01</span><span class="p">(</span><span class="n">only_lagged</span><span class="p">)</span>
        <span class="k">elif</span> <span class="n">rule</span> <span class="o">==</span> <span class="s2">&quot;ER-02&quot;</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_apply_ER02</span><span class="p">(</span><span class="n">only_lagged</span><span class="p">)</span>
        <span class="k">elif</span> <span class="n">rule</span> <span class="o">==</span> <span class="s2">&quot;ER-03&quot;</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_apply_ER03</span><span class="p">(</span><span class="n">only_lagged</span><span class="p">)</span>
        <span class="k">elif</span> <span class="n">rule</span> <span class="o">==</span> <span class="s2">&quot;R-04&quot;</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_apply_R04</span><span class="p">(</span><span class="n">only_lagged</span><span class="p">)</span>
        <span class="k">elif</span> <span class="n">rule</span> <span class="o">==</span> <span class="s2">&quot;ER-08&quot;</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_apply_ER08</span><span class="p">(</span><span class="n">only_lagged</span><span class="p">)</span>
        <span class="k">elif</span> <span class="n">rule</span> <span class="o">==</span> <span class="s2">&quot;ER-09&quot;</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_apply_ER09</span><span class="p">(</span><span class="n">only_lagged</span><span class="p">)</span>
        <span class="k">elif</span> <span class="n">rule</span> <span class="o">==</span> <span class="s2">&quot;ER-10&quot;</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_apply_ER10</span><span class="p">(</span><span class="n">only_lagged</span><span class="p">)</span>


    <span class="k">def</span> <span class="nf">_get_na_pds_t</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return the set na_pds_t(A, B), with at least one of them at lag 0&quot;&quot;&quot;</span>

        <span class="c1"># Unpack A and B, then assert that at least one of them is at lag 0</span>
        <span class="n">var_A</span><span class="p">,</span> <span class="n">lag_A</span> <span class="o">=</span> <span class="n">A</span>
        <span class="n">var_B</span><span class="p">,</span> <span class="n">lag_B</span> <span class="o">=</span> <span class="n">B</span>
        <span class="k">assert</span> <span class="n">lag_A</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">lag_B</span> <span class="o">==</span> <span class="mi">0</span>

        <span class="c1"># If na_pds_t(A, B) is in memory, return immediately</span>
        <span class="n">memo</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_na_pds_t</span><span class="p">[</span><span class="n">A</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">B</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">memo</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">memo</span>

        <span class="c1"># Else, re-compute na_pds_t(A, B) it according to the current graph and cache it.</span>

        <span class="c1"># Re-compute na_pds_t_1(A, B) according to the current graph</span>
        <span class="n">na_pds_t_1</span> <span class="o">=</span> <span class="p">{(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">lag_A</span><span class="p">)</span>
                    <span class="c1"># W = (var, lag + lag_A) is in na_pds_t_1(A, B) if ...</span>
                    <span class="k">for</span> <span class="p">((</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">),</span> <span class="n">link</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">var_A</span><span class="p">]</span><span class="o">.</span><span class="n">items</span><span class="p">()</span>
                    <span class="c1"># ... it is a non-future adjacency of A</span>
                    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">link</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span>
                    <span class="c1"># ... and is not B</span>
                    <span class="ow">and</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">lag_A</span><span class="p">)</span> <span class="o">!=</span> <span class="n">B</span>
                    <span class="c1"># ... and is not before t - tau_max</span>
                    <span class="ow">and</span> <span class="p">(</span><span class="n">lag</span> <span class="o">+</span> <span class="n">lag_A</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span>
                    <span class="c1"># ... and is not after both A and B</span>
                    <span class="c1"># ... (i.e. is not after time t)</span>
                    <span class="ow">and</span> <span class="p">(</span><span class="n">lag</span> <span class="o">+</span> <span class="n">lag_A</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mi">0</span>
                    <span class="c1"># ... and is not a definite non-ancestor of A,</span>
                    <span class="c1">#     which implies that it is not a definite descendant of A,</span>
                    <span class="ow">and</span> <span class="n">link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;&lt;&quot;</span>
                    <span class="c1"># ... and is not a definite descendant of B</span>
                    <span class="c1">#     (i.e., B is not a definite ancestor of W)</span>
                    <span class="ow">and</span> <span class="p">(</span><span class="n">var_B</span><span class="p">,</span> <span class="n">lag_B</span> <span class="o">-</span> <span class="p">(</span><span class="n">lag</span> <span class="o">+</span> <span class="n">lag_A</span><span class="p">))</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">def_ancs</span><span class="p">[</span><span class="n">var</span><span class="p">]</span>
                    <span class="p">}</span>

        <span class="c1"># Compute na_pds_t_2(A, B)</span>

        <span class="c1"># Find all potential C_1 nodes</span>
        <span class="n">C1_list</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
        <span class="k">for</span> <span class="p">((</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">),</span> <span class="n">link</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_full_dict</span><span class="p">[</span><span class="n">var_A</span><span class="p">]</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>

            <span class="n">node</span> <span class="o">=</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">lag_A</span><span class="p">)</span>

            <span class="c1"># node is added to C1_list if, in addition to being adjacent to A, ...</span>
            <span class="c1"># ... it is not B</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">lag_A</span><span class="p">)</span> <span class="o">==</span> <span class="n">B</span><span class="p">:</span>
                <span class="k">continue</span>

            <span class="c1"># ... it is not before t - tau_max</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">lag</span> <span class="o">+</span> <span class="n">lag_A</span><span class="p">)</span> <span class="o">&lt;</span> <span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">:</span>
                <span class="k">continue</span>

            <span class="c1"># ... it is not after B</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">lag</span> <span class="o">+</span> <span class="n">lag_A</span><span class="p">)</span> <span class="o">&gt;</span> <span class="n">lag_B</span><span class="p">:</span>
                <span class="k">continue</span>

            <span class="c1"># ... it is not a definite ancestor of A</span>
            <span class="k">if</span> <span class="n">link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;-&quot;</span><span class="p">:</span>
                <span class="k">continue</span>

            <span class="c1"># ... it is not a definite descendant of A</span>
            <span class="k">if</span> <span class="n">link</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;-&quot;</span><span class="p">:</span>
                <span class="k">continue</span>

            <span class="c1"># ... it is not a definite non-ancestor of B,</span>
            <span class="c1">#     which implies that it is not a definite descendant of B</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="p">(</span><span class="n">lag</span> <span class="o">+</span> <span class="n">lag_A</span><span class="p">)</span> <span class="o">-</span> <span class="n">lag_B</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">def_non_ancs</span><span class="p">[</span><span class="n">var_B</span><span class="p">]:</span>
                <span class="k">continue</span>

            <span class="c1"># If all tests are passed, node is added to C1_list</span>
            <span class="n">C1_list</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>

        <span class="c1"># end for ((var, lag), link) in self.graph_full_dict[var_A].items()</span>

        <span class="c1"># Breath first search to find (a superset of) na_pds_t_2(A, B)</span>

        <span class="n">visited</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
        <span class="n">start_from</span> <span class="o">=</span> <span class="p">{(</span><span class="n">C1</span><span class="p">,</span> <span class="n">A</span><span class="p">)</span> <span class="k">for</span> <span class="n">C1</span> <span class="ow">in</span> <span class="n">C1_list</span><span class="p">}</span>

        <span class="k">while</span> <span class="n">start_from</span><span class="p">:</span>

            <span class="n">new_start_from</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
            <span class="n">new_do_not_visit</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>

            <span class="k">for</span> <span class="p">(</span><span class="n">current_node</span><span class="p">,</span> <span class="n">previous_node</span><span class="p">)</span> <span class="ow">in</span> <span class="n">start_from</span><span class="p">:</span>

                <span class="n">visited</span><span class="o">.</span><span class="n">add</span><span class="p">((</span><span class="n">current_node</span><span class="p">,</span> <span class="n">previous_node</span><span class="p">))</span>

                <span class="k">for</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_full_dict</span><span class="p">[</span><span class="n">current_node</span><span class="p">[</span><span class="mi">0</span><span class="p">]]:</span>

                    <span class="n">next_node</span> <span class="o">=</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">current_node</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>

                    <span class="k">if</span> <span class="n">next_node</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&lt;</span> <span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">:</span>
                        <span class="k">continue</span>
                    <span class="k">if</span> <span class="n">next_node</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
                        <span class="k">continue</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">next_node</span><span class="p">,</span> <span class="n">current_node</span><span class="p">)</span> <span class="ow">in</span> <span class="n">visited</span><span class="p">:</span>
                        <span class="k">continue</span>
                    <span class="k">if</span> <span class="n">next_node</span> <span class="o">==</span> <span class="n">previous_node</span><span class="p">:</span>
                        <span class="k">continue</span>
                    <span class="k">if</span> <span class="n">next_node</span> <span class="o">==</span> <span class="n">B</span><span class="p">:</span>
                        <span class="k">continue</span>
                    <span class="k">if</span> <span class="n">next_node</span> <span class="o">==</span> <span class="n">A</span><span class="p">:</span>
                        <span class="k">continue</span>

                    <span class="n">link_l</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">next_node</span><span class="p">,</span> <span class="n">current_node</span><span class="p">)</span>
                    <span class="n">link_r</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">previous_node</span><span class="p">,</span> <span class="n">current_node</span><span class="p">)</span>

                    <span class="k">if</span> <span class="n">link_l</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;-&quot;</span> <span class="ow">or</span> <span class="n">link_r</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;-&quot;</span><span class="p">:</span>
                        <span class="k">continue</span>
                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">next_node</span><span class="p">,</span> <span class="n">previous_node</span><span class="p">)</span> <span class="o">==</span> <span class="s2">&quot;&quot;</span> <span class="ow">and</span> <span class="p">(</span><span class="n">link_l</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;o&quot;</span> <span class="ow">or</span> <span class="n">link_r</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;o&quot;</span><span class="p">):</span>
                        <span class="k">continue</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">var_A</span><span class="p">,</span> <span class="n">lag_A</span> <span class="o">-</span> <span class="n">next_node</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">def_ancs</span><span class="p">[</span><span class="n">next_node</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span> <span class="ow">or</span> <span class="p">(</span><span class="n">var_B</span><span class="p">,</span> <span class="n">lag_B</span> <span class="o">-</span> <span class="n">next_node</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">def_ancs</span><span class="p">[</span><span class="n">next_node</span><span class="p">[</span><span class="mi">0</span><span class="p">]]:</span>
                        <span class="k">continue</span>
                    <span class="k">if</span> <span class="p">((</span><span class="n">next_node</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">lag_A</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="ow">or</span> <span class="p">(</span><span class="n">next_node</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">next_node</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">lag_A</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">def_non_ancs</span><span class="p">[</span><span class="n">var_A</span><span class="p">])</span> <span class="ow">and</span> <span class="p">((</span><span class="n">next_node</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">lag_B</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="ow">or</span> <span class="p">(</span><span class="n">next_node</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">next_node</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">lag_B</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">def_non_ancs</span><span class="p">[</span><span class="n">var_B</span><span class="p">]):</span>
                        <span class="k">continue</span>

                    <span class="n">new_start_from</span><span class="o">.</span><span class="n">add</span><span class="p">((</span><span class="n">next_node</span><span class="p">,</span> <span class="n">current_node</span><span class="p">))</span>

            <span class="n">start_from</span> <span class="o">=</span> <span class="n">new_start_from</span>

        <span class="c1"># end  while start_from</span>

        <span class="n">na_pds_t_2</span> <span class="o">=</span> <span class="p">{</span><span class="n">node</span> <span class="k">for</span> <span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">_</span><span class="p">)</span> <span class="ow">in</span> <span class="n">visited</span><span class="p">}</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">_na_pds_t</span><span class="p">[</span><span class="n">A</span><span class="p">][</span><span class="n">B</span><span class="p">]</span> <span class="o">=</span> <span class="n">na_pds_t_1</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="n">na_pds_t_2</span><span class="p">)</span><span class="o">.</span><span class="n">difference</span><span class="p">({</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">})</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_na_pds_t</span><span class="p">[</span><span class="n">A</span><span class="p">][</span><span class="n">B</span><span class="p">]</span>


    <span class="k">def</span> <span class="nf">_make_sepset_weakly_minimal</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">Z_list</span><span class="p">,</span> <span class="n">ancs</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        X and Y are conditionally independent given Z in Z_list However, it is not yet clear whether any of these Z are minimal</span>
<span class="sd">        separating set.</span>

<span class="sd">        This function finds weakly minimal separating subsets in an order independent way and writes them to the self.sepsets</span>
<span class="sd">        dictionary. Only certainly weakly minimal separating subsets are retained.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="c1"># Assert that all Z in Z_list have the same cardinality</span>
        <span class="k">assert</span> <span class="nb">len</span><span class="p">({</span><span class="nb">len</span><span class="p">(</span><span class="n">Z</span><span class="p">)</span> <span class="k">for</span> <span class="n">Z</span> <span class="ow">in</span> <span class="n">Z_list</span><span class="p">})</span> <span class="o">==</span> <span class="mi">1</span>

        <span class="c1"># Base Case 1:</span>
        <span class="c1"># Z in Z_list is weakly minimal if len(Z) &lt;= 1 or Z \subset ancs</span>
        <span class="n">any_weakly_minimal</span> <span class="o">=</span> <span class="kc">False</span>

        <span class="k">for</span> <span class="n">Z</span> <span class="ow">in</span> <span class="n">Z_list</span><span class="p">:</span>

            <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">Z</span><span class="p">)</span> <span class="o">&lt;=</span><span class="mi">1</span> <span class="ow">or</span> <span class="n">Z</span><span class="o">.</span><span class="n">issubset</span><span class="p">(</span><span class="n">ancs</span><span class="p">):</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_save_sepset</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="p">(</span><span class="nb">frozenset</span><span class="p">(</span><span class="n">Z</span><span class="p">),</span> <span class="s2">&quot;wm&quot;</span><span class="p">))</span>
                <span class="n">any_weakly_minimal</span> <span class="o">=</span> <span class="kc">True</span>

        <span class="k">if</span> <span class="n">any_weakly_minimal</span><span class="p">:</span>
            <span class="k">return</span> <span class="kc">None</span>

        <span class="c1"># If not Base Case 1, we need to search for separating subsets. We do this for all Z in Z_list, and build a set sepsets_next_call</span>
        <span class="c1"># that contains all separating sets for the next recursive call</span>
        <span class="n">sepsets_next_call</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>

        <span class="k">for</span> <span class="n">Z</span> <span class="ow">in</span> <span class="n">Z_list</span><span class="p">:</span>

            <span class="c1"># Find all nodes A in Z that are not in ancs</span>
            <span class="n">removable</span> <span class="o">=</span> <span class="n">Z</span><span class="o">.</span><span class="n">difference</span><span class="p">(</span><span class="n">ancs</span><span class="p">)</span>

            <span class="c1"># Test for removal of all nodes in removable</span>
            <span class="n">new_sepsets</span> <span class="o">=</span> <span class="p">[]</span>
            <span class="n">val_values</span> <span class="o">=</span> <span class="p">[]</span>

            <span class="k">for</span> <span class="n">A</span> <span class="ow">in</span> <span class="n">removable</span><span class="p">:</span>

                <span class="n">Z_A</span> <span class="o">=</span> <span class="p">[</span><span class="n">node</span> <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">Z</span> <span class="k">if</span> <span class="n">node</span> <span class="o">!=</span> <span class="n">A</span><span class="p">]</span>

                <span class="c1"># Run the conditional independence test</span>
                <span class="c1"># val, pval = self.cond_ind_test.run_test(X = [X], Y = [Y], Z = Z_A, tau_max = self.tau_max)</span>
                <span class="n">val</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">dependent</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cond_ind_test</span><span class="o">.</span><span class="n">run_test</span><span class="p">(</span><span class="n">X</span> <span class="o">=</span> <span class="p">[</span><span class="n">X</span><span class="p">],</span> <span class="n">Y</span> <span class="o">=</span> <span class="p">[</span><span class="n">Y</span><span class="p">],</span> <span class="n">Z</span> <span class="o">=</span> <span class="n">Z_A</span><span class="p">,</span> 
                    <span class="n">tau_max</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">,</span> <span class="n">alpha_or_thres</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">pc_alpha</span><span class="p">)</span>

                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">:</span>
                    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;MakeMin:    </span><span class="si">%s</span><span class="s2"> _|_ </span><span class="si">%s</span><span class="s2">  |  Z_A = </span><span class="si">%s</span><span class="s2">: val = </span><span class="si">%.2f</span><span class="s2"> / pval = </span><span class="si">% .4f</span><span class="s2">&quot;</span> <span class="o">%</span>
                        <span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="nb">list</span><span class="p">(</span><span class="n">Z_A</span><span class="p">)]),</span> <span class="n">val</span><span class="p">,</span> <span class="n">pval</span><span class="p">))</span>

                <span class="c1"># Accordingly update dictionaries that keep track of the maximal p-value and the corresponding test statistic</span>
                <span class="c1"># values and conditioning set cardinalities</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_update_pval_val_card_dicts</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">val</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">Z_A</span><span class="p">))</span>

                <span class="c1"># Check whether the test result was significant</span>
                <span class="k">if</span> <span class="ow">not</span> <span class="n">dependent</span><span class="p">:</span> <span class="c1"># pval &gt; self.pc_alpha:</span>
                    <span class="n">new_sepsets</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">frozenset</span><span class="p">(</span><span class="n">Z_A</span><span class="p">))</span>
                    <span class="n">val_values</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">val</span><span class="p">)</span>

            <span class="c1"># If new_sepsets is empty, then Z is already weakly minimal</span>
            <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">new_sepsets</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_save_sepset</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="p">(</span><span class="nb">frozenset</span><span class="p">(</span><span class="n">Z</span><span class="p">),</span> <span class="s2">&quot;wm&quot;</span><span class="p">))</span>
                <span class="n">any_weakly_minimal</span> <span class="o">=</span> <span class="kc">True</span>

            <span class="c1"># If we did not yet find a weakly minimal separating set</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="n">any_weakly_minimal</span><span class="p">:</span>

                <span class="c1"># Sort all separating sets in new_sepets by their test statistic, then append those separating sets with maximal statistic</span>
                <span class="c1"># to sepsets_next_call. This i) guarantees order independence while ii) continuing to test as few as possible separating sets</span>
                <span class="n">new_sepsets</span> <span class="o">=</span> <span class="p">[</span><span class="n">node</span> <span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">node</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">val_values</span><span class="p">,</span> <span class="n">new_sepsets</span><span class="p">),</span> <span class="n">reverse</span> <span class="o">=</span> <span class="kc">True</span><span class="p">)]</span>

                <span class="n">i</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span>
                <span class="k">while</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="nb">len</span><span class="p">(</span><span class="n">val_values</span><span class="p">)</span> <span class="o">-</span> <span class="mi">2</span> <span class="ow">and</span> <span class="n">val_values</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">val_values</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span>
                    <span class="n">sepsets_next_call</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">new_sepsets</span><span class="p">[</span><span class="n">i</span><span class="p">])</span>
                    <span class="n">i</span> <span class="o">=</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span>

                <span class="k">assert</span> <span class="n">i</span> <span class="o">&gt;=</span> <span class="mi">0</span>

        <span class="c1"># If we did not yet find a weakly minimal separating set, make a recursive call</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">any_weakly_minimal</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_make_sepset_weakly_minimal</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">sepsets_next_call</span><span class="p">,</span> <span class="n">ancs</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">return</span> <span class="kc">None</span>


    <span class="k">def</span> <span class="nf">_B_not_in_SepSet_AC</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">C</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Is B in less than half of the sets in SepSets(A, C)?&quot;&quot;&quot;</span>

        <span class="c1"># Treat A - B - C as the same triple as C - B - A</span>
        <span class="c1"># Convention: A is before C or, if they are contemporaneous, the index of A is smaller than that of C</span>
        <span class="k">if</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="ow">or</span> <span class="p">(</span><span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="ow">and</span> <span class="n">C</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">A</span><span class="p">[</span><span class="mi">0</span><span class="p">]):</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_B_not_in_SepSet_AC</span><span class="p">(</span><span class="n">C</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">A</span><span class="p">)</span>

        <span class="c1"># Remember all separating sets that we will find</span>
        <span class="n">all_sepsets</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>

        <span class="c1"># Get the non-future adjacencies of A and C</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">use_a_pds_t_for_majority</span><span class="p">:</span>
            <span class="n">adj_A</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_non_future_adj</span><span class="p">([</span><span class="n">A</span><span class="p">])</span><span class="o">.</span><span class="n">difference</span><span class="p">({</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">})</span>
            <span class="n">adj_C</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_non_future_adj</span><span class="p">([</span><span class="n">C</span><span class="p">])</span><span class="o">.</span><span class="n">difference</span><span class="p">({</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">})</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">adj_A</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_a_pds_t</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">)</span><span class="o">.</span><span class="n">difference</span><span class="p">({</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">})</span>
            <span class="n">adj_C</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_a_pds_t</span><span class="p">(</span><span class="n">C</span><span class="p">,</span> <span class="n">A</span><span class="p">)</span><span class="o">.</span><span class="n">difference</span><span class="p">({</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">})</span>

        <span class="n">Z_add</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_parents</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">)</span><span class="o">.</span><span class="n">difference</span><span class="p">({</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">})</span>

        <span class="n">search_A</span> <span class="o">=</span> <span class="n">adj_A</span><span class="o">.</span><span class="n">difference</span><span class="p">(</span><span class="n">Z_add</span><span class="p">)</span>
        <span class="n">search_C</span> <span class="o">=</span> <span class="n">adj_C</span><span class="o">.</span><span class="n">difference</span><span class="p">(</span><span class="n">Z_add</span><span class="p">)</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="n">np</span><span class="o">.</span><span class="n">isinf</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">max_q_global</span><span class="p">):</span>
            <span class="n">search_A</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_sort_search_set</span><span class="p">(</span><span class="n">search_A</span><span class="p">,</span> <span class="n">A</span><span class="p">)</span>
            <span class="n">search_C</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_sort_search_set</span><span class="p">(</span><span class="n">search_C</span><span class="p">,</span> <span class="n">C</span><span class="p">)</span>

        <span class="c1"># Test for independence given all subsets of non-future adjacencies of A</span>
        <span class="k">if</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
            <span class="n">max_p_A</span> <span class="o">=</span> <span class="nb">min</span><span class="p">([</span><span class="nb">len</span><span class="p">(</span><span class="n">search_A</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_cond_px</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_p_global</span><span class="p">])</span> <span class="o">+</span> <span class="mi">1</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">max_p_A</span> <span class="o">=</span> <span class="nb">min</span><span class="p">([</span><span class="nb">len</span><span class="p">(</span><span class="n">search_A</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_p_global</span><span class="p">])</span> <span class="o">+</span> <span class="mi">1</span>

        <span class="c1"># Shift lags</span>
        <span class="n">search_A</span> <span class="o">=</span> <span class="p">[(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">-</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="k">for</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">)</span> <span class="ow">in</span> <span class="n">search_A</span><span class="p">]</span>
        <span class="n">search_C</span> <span class="o">=</span> <span class="p">[(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">-</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="k">for</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">)</span> <span class="ow">in</span> <span class="n">search_C</span><span class="p">]</span>
        <span class="n">Z_add</span> <span class="o">=</span> <span class="p">{(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">-</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="k">for</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">)</span> <span class="ow">in</span> <span class="n">Z_add</span><span class="p">}</span>
        <span class="n">X</span> <span class="o">=</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
        <span class="n">Y</span> <span class="o">=</span> <span class="p">(</span><span class="n">C</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="mi">0</span><span class="p">)</span>

        <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">max_p_A</span><span class="p">):</span>

            <span class="n">q_count</span> <span class="o">=</span> <span class="mi">0</span>
            <span class="k">for</span> <span class="n">Z_raw</span> <span class="ow">in</span> <span class="n">combinations</span><span class="p">(</span><span class="n">search_A</span><span class="p">,</span> <span class="n">p</span><span class="p">):</span>

                <span class="n">q_count</span> <span class="o">=</span> <span class="n">q_count</span> <span class="o">+</span> <span class="mi">1</span>
                <span class="k">if</span> <span class="n">q_count</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_q_global</span><span class="p">:</span>
                    <span class="k">break</span>

                <span class="c1"># Prepare the conditioning set</span>
                <span class="n">Z</span> <span class="o">=</span> <span class="p">{</span><span class="n">node</span> <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">Z_raw</span> <span class="k">if</span> <span class="n">node</span> <span class="o">!=</span> <span class="n">X</span> <span class="ow">and</span> <span class="n">node</span> <span class="o">!=</span> <span class="n">Y</span><span class="p">}</span>
                <span class="n">Z</span> <span class="o">=</span> <span class="n">Z</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="n">Z_add</span><span class="p">)</span>

                <span class="c1"># Test conditional independence of X and Y given Z</span>
                <span class="c1"># val, pval = self.cond_ind_test.run_test(X = [X], Y = [Y], Z = list(Z), tau_max = self.tau_max)</span>
                <span class="n">val</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">dependent</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cond_ind_test</span><span class="o">.</span><span class="n">run_test</span><span class="p">(</span><span class="n">X</span> <span class="o">=</span> <span class="p">[</span><span class="n">X</span><span class="p">],</span> <span class="n">Y</span> <span class="o">=</span> <span class="p">[</span><span class="n">Y</span><span class="p">],</span> <span class="n">Z</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">Z</span><span class="p">),</span> 
                    <span class="n">tau_max</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">,</span> <span class="n">alpha_or_thres</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">pc_alpha</span><span class="p">)</span>

                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">:</span>
                    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;BnotinSepSetAC(A):    </span><span class="si">%s</span><span class="s2"> _|_ </span><span class="si">%s</span><span class="s2">  |  Z_add = </span><span class="si">%s</span><span class="s2">, Z = </span><span class="si">%s</span><span class="s2">: val = </span><span class="si">%.2f</span><span class="s2"> / pval = </span><span class="si">% .4f</span><span class="s2">&quot;</span> <span class="o">%</span>
                        <span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="n">Z_add</span><span class="p">]),</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="p">{</span><span class="n">node</span> <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">Z_raw</span> <span class="k">if</span> <span class="n">node</span> <span class="o">!=</span> <span class="n">X</span> <span class="ow">and</span> <span class="n">node</span> <span class="o">!=</span> <span class="n">Y</span><span class="p">}]),</span> <span class="n">val</span><span class="p">,</span> <span class="n">pval</span><span class="p">))</span>

                <span class="c1"># Accordingly update dictionaries that keep track of the maximal p-value and the corresponding test statistic</span>
                <span class="c1"># values and conditioning set cardinalities</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_update_pval_val_card_dicts</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">val</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">Z</span><span class="p">))</span>

                <span class="c1"># Check whether test result was significant</span>
                <span class="k">if</span> <span class="ow">not</span> <span class="n">dependent</span><span class="p">:</span> <span class="c1"># pval &gt; self.pc_alpha:</span>
                    <span class="n">all_sepsets</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="nb">frozenset</span><span class="p">(</span><span class="n">Z</span><span class="p">))</span>

        <span class="c1"># Test for independence given all subsets of non-future adjacencies of C</span>
        <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">min</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">search_C</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_p_global</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">):</span>

            <span class="n">q_count</span> <span class="o">=</span> <span class="mi">0</span> 
            <span class="k">for</span> <span class="n">Z_raw</span> <span class="ow">in</span> <span class="n">combinations</span><span class="p">(</span><span class="n">search_C</span><span class="p">,</span> <span class="n">p</span><span class="p">):</span>

                <span class="n">q_count</span> <span class="o">=</span> <span class="n">q_count</span> <span class="o">+</span> <span class="mi">1</span>
                <span class="k">if</span> <span class="n">q_count</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_q_global</span><span class="p">:</span>
                    <span class="k">break</span>

                <span class="c1"># Prepare the conditioning set</span>
                <span class="n">Z</span> <span class="o">=</span> <span class="p">{</span><span class="n">node</span> <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">Z_raw</span> <span class="k">if</span> <span class="n">node</span> <span class="o">!=</span> <span class="n">X</span> <span class="ow">and</span> <span class="n">node</span> <span class="o">!=</span> <span class="n">Y</span><span class="p">}</span>
                <span class="n">Z</span> <span class="o">=</span> <span class="n">Z</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="n">Z_add</span><span class="p">)</span>

                <span class="c1"># Test conditional independence of X and Y given Z</span>
                <span class="c1"># val, pval = self.cond_ind_test.run_test(X = [X], Y = [Y], Z = list(Z), tau_max = self.tau_max)</span>
                <span class="n">val</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">dependent</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cond_ind_test</span><span class="o">.</span><span class="n">run_test</span><span class="p">(</span><span class="n">X</span> <span class="o">=</span> <span class="p">[</span><span class="n">X</span><span class="p">],</span> <span class="n">Y</span> <span class="o">=</span> <span class="p">[</span><span class="n">Y</span><span class="p">],</span> <span class="n">Z</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">Z</span><span class="p">),</span> 
                    <span class="n">tau_max</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">,</span> <span class="n">alpha_or_thres</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">pc_alpha</span><span class="p">)</span>

                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">:</span>
                    <span class="c1"># print(&quot;BnotinSepSetAC(C):    %s _|_ %s  |  Z = %s: val = %.2f / pval = % .4f&quot; %</span>
                    <span class="c1">#     (X, Y, &#39; &#39;.join([str(z) for z in list(Z)]), val, pval))</span>
                    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;BnotinSepSetAC(C):    </span><span class="si">%s</span><span class="s2"> _|_ </span><span class="si">%s</span><span class="s2">  |  Z_add = </span><span class="si">%s</span><span class="s2">, Z = </span><span class="si">%s</span><span class="s2">: val = </span><span class="si">%.2f</span><span class="s2"> / pval = </span><span class="si">% .4f</span><span class="s2">&quot;</span> <span class="o">%</span>
                        <span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="n">Z_add</span><span class="p">]),</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="p">{</span><span class="n">node</span> <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">Z_raw</span> <span class="k">if</span> <span class="n">node</span> <span class="o">!=</span> <span class="n">X</span> <span class="ow">and</span> <span class="n">node</span> <span class="o">!=</span> <span class="n">Y</span><span class="p">}]),</span> <span class="n">val</span><span class="p">,</span> <span class="n">pval</span><span class="p">))</span>

                <span class="c1"># Accordingly update dictionaries that keep track of the maximal p-value and the corresponding test statistic</span>
                <span class="c1"># values and conditioning set cardinalities</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_update_pval_val_card_dicts</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">val</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">Z</span><span class="p">))</span>

                <span class="c1"># Check whether test result was significant</span>
                <span class="k">if</span> <span class="ow">not</span> <span class="n">dependent</span><span class="p">:</span> <span class="c1"># pval &gt; self.pc_alpha:</span>
                    <span class="n">all_sepsets</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="nb">frozenset</span><span class="p">(</span><span class="n">Z</span><span class="p">))</span>

        <span class="c1"># Append the already known sepset</span>
        <span class="n">all_sepsets</span> <span class="o">=</span> <span class="n">all_sepsets</span><span class="o">.</span><span class="n">union</span><span class="p">({</span><span class="n">Z</span> <span class="k">for</span> <span class="p">(</span><span class="n">Z</span><span class="p">,</span> <span class="n">_</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_sepsets</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">)})</span>

        <span class="c1"># Count number of sepsets and number of sepsets that contain B</span>
        <span class="n">n_sepsets</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">all_sepsets</span><span class="p">)</span>
        <span class="n">n_sepsets_with_B</span> <span class="o">=</span> <span class="nb">len</span><span class="p">([</span><span class="mi">1</span> <span class="k">for</span> <span class="n">Z</span> <span class="ow">in</span> <span class="n">all_sepsets</span> <span class="k">if</span> <span class="p">(</span><span class="n">B</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">B</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="ow">in</span> <span class="n">Z</span><span class="p">])</span>

        <span class="k">return</span> <span class="kc">True</span> <span class="k">if</span> <span class="mi">2</span><span class="o">*</span><span class="n">n_sepsets_with_B</span> <span class="o">&lt;</span> <span class="n">n_sepsets</span> <span class="k">else</span> <span class="kc">False</span>


    <span class="k">def</span> <span class="nf">_B_in_SepSet_AC</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">C</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Is B in more than half of the sets in SepSets(A, C)?&quot;&quot;&quot;</span>

        <span class="c1"># Treat A - B - C as the same triple as C - B - A</span>
        <span class="c1"># Convention: A is before C or, if they are contemporaneous, the index of A is smaller than that of C</span>
        <span class="k">if</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="ow">or</span> <span class="p">(</span><span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="ow">and</span> <span class="n">C</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">A</span><span class="p">[</span><span class="mi">0</span><span class="p">]):</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_B_in_SepSet_AC</span><span class="p">(</span><span class="n">C</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">A</span><span class="p">)</span>

        <span class="n">link_AB</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">)</span>
        <span class="n">link_CB</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">C</span><span class="p">,</span> <span class="n">B</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">link_AB</span> <span class="o">==</span> <span class="s2">&quot;&quot;</span> <span class="ow">or</span> <span class="n">link_CB</span> <span class="o">==</span> <span class="s2">&quot;&quot;</span> <span class="ow">or</span> <span class="n">link_AB</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;-&quot;</span> <span class="ow">or</span> <span class="n">link_CB</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;-&quot;</span><span class="p">:</span>

            <span class="c1"># Vote is based on those sets that where found already</span>
            <span class="n">all_sepsets</span> <span class="o">=</span> <span class="p">{</span><span class="n">Z</span> <span class="k">for</span> <span class="p">(</span><span class="n">Z</span><span class="p">,</span> <span class="n">_</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_sepsets</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">)}</span>

            <span class="c1"># Count number of sepsets and number of sepsets that contain B</span>
            <span class="n">n_sepsets</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">all_sepsets</span><span class="p">)</span>
            <span class="n">n_sepsets_with_B</span> <span class="o">=</span> <span class="nb">len</span><span class="p">([</span><span class="mi">1</span> <span class="k">for</span> <span class="n">Z</span> <span class="ow">in</span> <span class="n">all_sepsets</span> <span class="k">if</span> <span class="n">B</span> <span class="ow">in</span> <span class="n">Z</span><span class="p">])</span>

            <span class="k">return</span> <span class="kc">True</span> <span class="k">if</span> <span class="mi">2</span><span class="o">*</span><span class="n">n_sepsets_with_B</span> <span class="o">&gt;</span> <span class="n">n_sepsets</span> <span class="k">else</span> <span class="kc">False</span>

        <span class="k">else</span><span class="p">:</span>

            <span class="c1"># Remember all separating sets that we will find</span>
            <span class="n">all_sepsets</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>

            <span class="c1"># Get the non-future adjacencies of A and C</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">use_a_pds_t_for_majority</span><span class="p">:</span>
                <span class="n">adj_A</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_non_future_adj</span><span class="p">([</span><span class="n">A</span><span class="p">])</span><span class="o">.</span><span class="n">difference</span><span class="p">({</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">})</span>
                <span class="n">adj_C</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_non_future_adj</span><span class="p">([</span><span class="n">C</span><span class="p">])</span><span class="o">.</span><span class="n">difference</span><span class="p">({</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">})</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">adj_A</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_a_pds_t</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">)</span><span class="o">.</span><span class="n">difference</span><span class="p">({</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">})</span>
                <span class="n">adj_C</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_a_pds_t</span><span class="p">(</span><span class="n">C</span><span class="p">,</span> <span class="n">A</span><span class="p">)</span><span class="o">.</span><span class="n">difference</span><span class="p">({</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">})</span>

            <span class="n">Z_add</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_parents</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">)</span><span class="o">.</span><span class="n">difference</span><span class="p">({</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">})</span>

            <span class="n">search_A</span> <span class="o">=</span> <span class="n">adj_A</span><span class="o">.</span><span class="n">difference</span><span class="p">(</span><span class="n">Z_add</span><span class="p">)</span>
            <span class="n">search_C</span> <span class="o">=</span> <span class="n">adj_C</span><span class="o">.</span><span class="n">difference</span><span class="p">(</span><span class="n">Z_add</span><span class="p">)</span>

            <span class="k">if</span> <span class="ow">not</span> <span class="n">np</span><span class="o">.</span><span class="n">isinf</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">max_q_global</span><span class="p">):</span>
                <span class="n">search_A</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_sort_search_set</span><span class="p">(</span><span class="n">search_A</span><span class="p">,</span> <span class="n">A</span><span class="p">)</span>
                <span class="n">search_C</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_sort_search_set</span><span class="p">(</span><span class="n">search_C</span><span class="p">,</span> <span class="n">C</span><span class="p">)</span>

            <span class="c1"># Test for independence given all subsets of non-future adjacencies of A</span>
            <span class="k">if</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
                <span class="n">max_p_A</span> <span class="o">=</span> <span class="nb">min</span><span class="p">([</span><span class="nb">len</span><span class="p">(</span><span class="n">search_A</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_cond_px</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_p_global</span><span class="p">])</span> <span class="o">+</span> <span class="mi">1</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">max_p_A</span> <span class="o">=</span> <span class="nb">min</span><span class="p">([</span><span class="nb">len</span><span class="p">(</span><span class="n">search_A</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_p_global</span><span class="p">])</span> <span class="o">+</span> <span class="mi">1</span>

            <span class="c1"># Shift lags</span>
            <span class="n">search_A</span> <span class="o">=</span> <span class="p">[(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">-</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="k">for</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">)</span> <span class="ow">in</span> <span class="n">search_A</span><span class="p">]</span>
            <span class="n">search_C</span> <span class="o">=</span> <span class="p">[(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">-</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="k">for</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">)</span> <span class="ow">in</span> <span class="n">search_C</span><span class="p">]</span>
            <span class="n">Z_add</span> <span class="o">=</span> <span class="p">{(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">-</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="k">for</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">)</span> <span class="ow">in</span> <span class="n">Z_add</span><span class="p">}</span>
            <span class="n">X</span> <span class="o">=</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
            <span class="n">Y</span> <span class="o">=</span> <span class="p">(</span><span class="n">C</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="mi">0</span><span class="p">)</span>

            <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">max_p_A</span><span class="p">):</span>

                <span class="n">q_count</span> <span class="o">=</span> <span class="mi">0</span>
                <span class="k">for</span> <span class="n">Z_raw</span> <span class="ow">in</span> <span class="n">combinations</span><span class="p">(</span><span class="n">search_A</span><span class="p">,</span> <span class="n">p</span><span class="p">):</span>

                    <span class="n">q_count</span> <span class="o">=</span> <span class="n">q_count</span> <span class="o">+</span> <span class="mi">1</span>
                    <span class="k">if</span> <span class="n">q_count</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_q_global</span><span class="p">:</span>
                        <span class="k">break</span>

                    <span class="c1"># Prepare the conditioning set</span>
                    <span class="n">Z</span> <span class="o">=</span> <span class="p">{</span><span class="n">node</span> <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">Z_raw</span> <span class="k">if</span> <span class="n">node</span> <span class="o">!=</span> <span class="n">X</span> <span class="ow">and</span> <span class="n">node</span> <span class="o">!=</span> <span class="n">Y</span><span class="p">}</span>
                    <span class="n">Z</span> <span class="o">=</span> <span class="n">Z</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="n">Z_add</span><span class="p">)</span>

                    <span class="c1"># Test conditional independence of X and Y given Z</span>
                    <span class="c1"># val, pval = self.cond_ind_test.run_test(X = [X], Y = [Y], Z = list(Z), tau_max = self.tau_max)</span>
                    <span class="n">val</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">dependent</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cond_ind_test</span><span class="o">.</span><span class="n">run_test</span><span class="p">(</span><span class="n">X</span> <span class="o">=</span> <span class="p">[</span><span class="n">X</span><span class="p">],</span> <span class="n">Y</span> <span class="o">=</span> <span class="p">[</span><span class="n">Y</span><span class="p">],</span> <span class="n">Z</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">Z</span><span class="p">),</span> 
                        <span class="n">tau_max</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">,</span> <span class="n">alpha_or_thres</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">pc_alpha</span><span class="p">)</span>
                    
                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">:</span>
                        <span class="c1"># print(&quot;BinSepSetAC(A):    %s _|_ %s  |  Z = %s: val = %.2f / pval = % .4f&quot; %</span>
                        <span class="c1">#     (X, Y, &#39; &#39;.join([str(z) for z in list(Z)]), val, pval))</span>
                        <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;BinSepSetAC(A):    </span><span class="si">%s</span><span class="s2"> _|_ </span><span class="si">%s</span><span class="s2">  |  Z_add = </span><span class="si">%s</span><span class="s2">, Z = </span><span class="si">%s</span><span class="s2">: val = </span><span class="si">%.2f</span><span class="s2"> / pval = </span><span class="si">% .4f</span><span class="s2">&quot;</span> <span class="o">%</span>
                            <span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="n">Z_add</span><span class="p">]),</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="p">{</span><span class="n">node</span> <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">Z_raw</span> <span class="k">if</span> <span class="n">node</span> <span class="o">!=</span> <span class="n">X</span> <span class="ow">and</span> <span class="n">node</span> <span class="o">!=</span> <span class="n">Y</span><span class="p">}]),</span> <span class="n">val</span><span class="p">,</span> <span class="n">pval</span><span class="p">))</span>

                    <span class="c1"># Accordingly update dictionaries that keep track of the maximal p-value and the corresponding test statistic</span>
                    <span class="c1"># values and conditioning set cardinalities</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_update_pval_val_card_dicts</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">val</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">Z</span><span class="p">))</span>

                    <span class="c1"># Check whether test result was significant</span>
                    <span class="k">if</span> <span class="ow">not</span> <span class="n">dependent</span><span class="p">:</span> <span class="c1"># pval &gt; self.pc_alpha:</span>
                        <span class="n">all_sepsets</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="nb">frozenset</span><span class="p">(</span><span class="n">Z</span><span class="p">))</span>

            <span class="c1"># Test for independence given all subsets of non-future adjacencies of C</span>
            <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">min</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">search_C</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_p_global</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">):</span>

                <span class="n">q_count</span> <span class="o">=</span> <span class="mi">0</span> 
                <span class="k">for</span> <span class="n">Z_raw</span> <span class="ow">in</span> <span class="n">combinations</span><span class="p">(</span><span class="n">search_C</span><span class="p">,</span> <span class="n">p</span><span class="p">):</span>

                    <span class="n">q_count</span> <span class="o">=</span> <span class="n">q_count</span> <span class="o">+</span> <span class="mi">1</span>
                    <span class="k">if</span> <span class="n">q_count</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_q_global</span><span class="p">:</span>
                        <span class="k">break</span>

                    <span class="c1"># Prepare the conditioning set</span>
                    <span class="n">Z</span> <span class="o">=</span> <span class="p">{</span><span class="n">node</span> <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">Z_raw</span> <span class="k">if</span> <span class="n">node</span> <span class="o">!=</span> <span class="n">X</span> <span class="ow">and</span> <span class="n">node</span> <span class="o">!=</span> <span class="n">Y</span><span class="p">}</span>
                    <span class="n">Z</span> <span class="o">=</span> <span class="n">Z</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="n">Z_add</span><span class="p">)</span>

                    <span class="c1"># Test conditional independence of X and Y given Z</span>
                    <span class="c1"># val, pval = self.cond_ind_test.run_test(X = [X], Y = [Y], Z = list(Z), tau_max = self.tau_max)</span>
                    <span class="n">val</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">dependent</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cond_ind_test</span><span class="o">.</span><span class="n">run_test</span><span class="p">(</span><span class="n">X</span> <span class="o">=</span> <span class="p">[</span><span class="n">X</span><span class="p">],</span> <span class="n">Y</span> <span class="o">=</span> <span class="p">[</span><span class="n">Y</span><span class="p">],</span> <span class="n">Z</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">Z</span><span class="p">),</span> 
                        <span class="n">tau_max</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">,</span> <span class="n">alpha_or_thres</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">pc_alpha</span><span class="p">)</span>
                    
                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">:</span>
                        <span class="c1"># print(&quot;BinSepSetAC(C):     %s _|_ %s  |  Z = %s: val = %.2f / pval = % .4f&quot; %</span>
                        <span class="c1">#     (X, Y, &#39; &#39;.join([str(z) for z in list(Z)]), val, pval))</span>
                        <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;BinSepSetAC(C):    </span><span class="si">%s</span><span class="s2"> _|_ </span><span class="si">%s</span><span class="s2">  |  Z_add = </span><span class="si">%s</span><span class="s2">, Z = </span><span class="si">%s</span><span class="s2">: val = </span><span class="si">%.2f</span><span class="s2"> / pval = </span><span class="si">% .4f</span><span class="s2">&quot;</span> <span class="o">%</span>
                            <span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="n">Z_add</span><span class="p">]),</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="p">{</span><span class="n">node</span> <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">Z_raw</span> <span class="k">if</span> <span class="n">node</span> <span class="o">!=</span> <span class="n">X</span> <span class="ow">and</span> <span class="n">node</span> <span class="o">!=</span> <span class="n">Y</span><span class="p">}]),</span> <span class="n">val</span><span class="p">,</span> <span class="n">pval</span><span class="p">))</span>

                    <span class="c1"># Accordingly update dictionaries that keep track of the maximal p-value and the corresponding test statistic</span>
                    <span class="c1"># values and conditioning set cardinalities</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_update_pval_val_card_dicts</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">val</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">Z</span><span class="p">))</span>

                    <span class="c1"># Check whether test result was significant</span>
                    <span class="k">if</span> <span class="ow">not</span> <span class="n">dependent</span><span class="p">:</span> <span class="c1"># pval &gt; self.pc_alpha:</span>
                        <span class="n">all_sepsets</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="nb">frozenset</span><span class="p">(</span><span class="n">Z</span><span class="p">))</span>

            <span class="c1"># Append the already known sepset</span>
            <span class="n">all_sepsets</span> <span class="o">=</span> <span class="n">all_sepsets</span><span class="o">.</span><span class="n">union</span><span class="p">({</span><span class="n">Z</span> <span class="k">for</span> <span class="p">(</span><span class="n">Z</span><span class="p">,</span> <span class="n">_</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_sepsets</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">)})</span>

            <span class="c1"># Count number of sepsets and number of sepsets that contain B</span>
            <span class="n">n_sepsets</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">all_sepsets</span><span class="p">)</span>
            <span class="n">n_sepsets_with_B</span> <span class="o">=</span> <span class="nb">len</span><span class="p">([</span><span class="mi">1</span> <span class="k">for</span> <span class="n">Z</span> <span class="ow">in</span> <span class="n">all_sepsets</span> <span class="k">if</span> <span class="p">(</span><span class="n">B</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">B</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="ow">in</span> <span class="n">Z</span><span class="p">])</span>

            <span class="k">return</span> <span class="kc">True</span> <span class="k">if</span> <span class="mi">2</span><span class="o">*</span><span class="n">n_sepsets_with_B</span> <span class="o">&gt;</span> <span class="n">n_sepsets</span> <span class="k">else</span> <span class="kc">False</span>


    <span class="k">def</span> <span class="nf">_get_parents</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return all known parents of all nodes in node_list&quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">parents_of_lagged</span> <span class="ow">or</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">B</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>

            <span class="n">out</span> <span class="o">=</span> <span class="p">{(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="k">for</span> <span class="p">((</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">),</span> <span class="n">link</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">A</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">link</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;-&quot;</span> <span class="ow">and</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">}</span>
            <span class="k">return</span> <span class="n">out</span><span class="o">.</span><span class="n">union</span><span class="p">({(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">B</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="k">for</span> <span class="p">((</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">),</span> <span class="n">link</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">B</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">link</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;-&quot;</span> <span class="ow">and</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">B</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">})</span>

        <span class="k">else</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">B</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
                <span class="k">return</span> <span class="p">{(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">B</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="k">for</span> <span class="p">((</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">),</span> <span class="n">link</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">B</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">link</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;-&quot;</span> <span class="ow">and</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">B</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">}</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="k">return</span> <span class="p">{(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="k">for</span> <span class="p">((</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">),</span> <span class="n">link</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">A</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">link</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;-&quot;</span> <span class="ow">and</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">}</span>


    <span class="k">def</span> <span class="nf">_apply_middle_mark</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">char</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Update the middle mark on the link between X and Y with the character char&quot;&quot;&quot;</span>

        <span class="c1"># Get the old link</span>
        <span class="n">old_link</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">)</span>

        <span class="c1"># Determine the new link</span>
        <span class="k">if</span> <span class="n">old_link</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;?&quot;</span><span class="p">:</span>
            <span class="n">new_link</span> <span class="o">=</span> <span class="n">old_link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">char</span> <span class="o">+</span> <span class="n">old_link</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
        <span class="k">elif</span> <span class="p">(</span><span class="n">old_link</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;L&quot;</span> <span class="ow">and</span> <span class="n">char</span> <span class="o">==</span> <span class="s2">&quot;R&quot;</span><span class="p">)</span> <span class="ow">or</span> <span class="p">(</span><span class="n">old_link</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;R&quot;</span> <span class="ow">and</span> <span class="n">char</span> <span class="o">==</span> <span class="s2">&quot;L&quot;</span><span class="p">):</span>
            <span class="n">new_link</span> <span class="o">=</span> <span class="n">old_link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;!&quot;</span> <span class="o">+</span> <span class="n">old_link</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">assert</span> <span class="kc">False</span>

        <span class="c1"># Write the new link</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_write_link</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">new_link</span><span class="p">,</span> <span class="n">verbosity</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span><span class="p">)</span>

        <span class="c1"># Return</span>
        <span class="k">return</span> <span class="kc">True</span>


    <span class="k">def</span> <span class="nf">_update_middle_marks</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Apply rule MMR&quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
            <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">Middle mark updates</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span>

        <span class="c1"># Run through all links</span>
        <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">):</span>
            <span class="k">for</span> <span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="n">link</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>

                <span class="k">if</span> <span class="n">link</span> <span class="o">==</span> <span class="s2">&quot;&quot;</span><span class="p">:</span>
                    <span class="k">continue</span>

                <span class="n">X</span> <span class="o">=</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span>
                <span class="n">Y</span> <span class="o">=</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>

                <span class="c1"># Apply above rule for A = X and B = Y</span>
                <span class="n">link_XY</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">)</span>
                <span class="n">smaller_XY</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_smaller</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">)</span>

                <span class="k">if</span> <span class="n">link_XY</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;&gt;&quot;</span><span class="p">:</span>

                    <span class="k">if</span> <span class="n">link_XY</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;?&quot;</span><span class="p">:</span>
                        <span class="k">if</span> <span class="n">smaller_XY</span><span class="p">:</span>
                            <span class="n">new_link</span> <span class="o">=</span> <span class="n">link_XY</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;L&gt;&quot;</span>
                        <span class="k">else</span><span class="p">:</span>
                            <span class="n">new_link</span> <span class="o">=</span> <span class="n">link_XY</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;R&gt;&quot;</span>

                        <span class="bp">self</span><span class="o">.</span><span class="n">_write_link</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">new_link</span><span class="p">,</span> <span class="n">verbosity</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span><span class="p">)</span>

                    <span class="k">elif</span> <span class="p">(</span><span class="n">link_XY</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;R&quot;</span> <span class="ow">and</span> <span class="n">smaller_XY</span><span class="p">)</span> <span class="ow">or</span> <span class="p">(</span><span class="n">link_XY</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;L&quot;</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">smaller_XY</span><span class="p">):</span>

                        <span class="n">new_link</span> <span class="o">=</span> <span class="n">link_XY</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;!&gt;&quot;</span>

                        <span class="bp">self</span><span class="o">.</span><span class="n">_write_link</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">new_link</span><span class="p">,</span> <span class="n">verbosity</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span><span class="p">)</span>


                <span class="c1"># Apply above rule for A = Y and B = X</span>
                <span class="n">link_YX</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">Y</span><span class="p">,</span> <span class="n">X</span><span class="p">)</span>
                <span class="n">smaller_YX</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_smaller</span><span class="p">(</span><span class="n">Y</span><span class="p">,</span> <span class="n">X</span><span class="p">)</span>

                <span class="k">if</span> <span class="n">link_YX</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;&gt;&quot;</span><span class="p">:</span>

                    <span class="k">if</span> <span class="n">link_YX</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;?&quot;</span><span class="p">:</span>
                        <span class="k">if</span> <span class="n">smaller_YX</span><span class="p">:</span>
                            <span class="n">new_link</span> <span class="o">=</span> <span class="n">link_YX</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;L&gt;&quot;</span>
                        <span class="k">else</span><span class="p">:</span>
                            <span class="n">new_link</span> <span class="o">=</span> <span class="n">link_YX</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;R&gt;&quot;</span>

                        <span class="bp">self</span><span class="o">.</span><span class="n">_write_link</span><span class="p">(</span><span class="n">Y</span><span class="p">,</span> <span class="n">X</span><span class="p">,</span> <span class="n">new_link</span><span class="p">,</span> <span class="n">verbosity</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span><span class="p">)</span>
   

                    <span class="k">elif</span> <span class="p">(</span><span class="n">link_YX</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;R&quot;</span> <span class="ow">and</span> <span class="n">smaller_YX</span><span class="p">)</span> <span class="ow">or</span> <span class="p">(</span><span class="n">link_YX</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;L&quot;</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">smaller_YX</span><span class="p">):</span>

                        <span class="n">new_link</span> <span class="o">=</span> <span class="n">link_YX</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;!&gt;&quot;</span>

                        <span class="bp">self</span><span class="o">.</span><span class="n">_write_link</span><span class="p">(</span><span class="n">Y</span><span class="p">,</span> <span class="n">X</span><span class="p">,</span> <span class="n">new_link</span><span class="p">,</span> <span class="n">verbosity</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span><span class="p">)</span>
    
    <span class="k">def</span> <span class="nf">_is_smaller</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        A node X is said to be smaller than node Y if</span>
<span class="sd">        i)  X is before Y or</span>
<span class="sd">        ii) X and Y are contemporaneous and the variable index of X is smaller than that of Y.</span>

<span class="sd">        Return True if X is smaller than Y, else return False</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="k">return</span> <span class="p">(</span><span class="n">X</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">Y</span> <span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="ow">or</span> <span class="p">(</span><span class="n">X</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">Y</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="ow">and</span> <span class="n">X</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">Y</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>           


    <span class="k">def</span> <span class="nf">_get_a_pds_t</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return the set a_pds_t(A, B)&quot;&quot;&quot;</span>

        <span class="c1"># Unpack A and assert that A is at lag 0</span>
        <span class="n">var_A</span><span class="p">,</span> <span class="n">lag_A</span> <span class="o">=</span> <span class="n">A</span>

        <span class="c1"># Compute a_pds_t(A, B) according to the current graph</span>
        <span class="k">return</span> <span class="p">{(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">lag_A</span><span class="p">)</span>
                    <span class="c1"># W = (var, lag) is in a_pds_t(A, B) if ...</span>
                    <span class="k">for</span> <span class="p">((</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">),</span> <span class="n">link</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">var_A</span><span class="p">]</span><span class="o">.</span><span class="n">items</span><span class="p">()</span>
                    <span class="c1"># ... it is a non-future adjacency of A</span>
                    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">link</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span>
                    <span class="c1"># ... and it is not B</span>
                    <span class="ow">and</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">lag_A</span><span class="p">)</span> <span class="o">!=</span> <span class="n">B</span>
                    <span class="c1"># ... it is not before t - self.tau_max</span>
                    <span class="ow">and</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">lag_A</span> <span class="o">&gt;=</span> <span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span>
                    <span class="c1"># ... and it is not a definite non-ancestor of A</span>
                    <span class="ow">and</span> <span class="n">link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;&lt;&quot;</span>
                    <span class="p">}</span>


    <span class="k">def</span> <span class="nf">_get_ancs</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">node_list</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return the currently known set of ancestors of all nodes in the list node_list. The nodes are not required to be at</span>
<span class="sd">        lag 0&quot;&quot;&quot;</span>

        <span class="c1"># Build the output set</span>
        <span class="n">out</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>

        <span class="c1"># Run through all nodes</span>
        <span class="k">for</span> <span class="n">A</span> <span class="ow">in</span> <span class="n">node_list</span><span class="p">:</span>
            <span class="c1"># Unpack the node</span>
            <span class="p">(</span><span class="n">var_A</span><span class="p">,</span> <span class="n">lag_A</span><span class="p">)</span> <span class="o">=</span> <span class="n">A</span>
            <span class="c1"># Add the ancestors of node to out</span>
            <span class="n">out</span> <span class="o">=</span> <span class="n">out</span><span class="o">.</span><span class="n">union</span><span class="p">({(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">lag_A</span><span class="p">)</span> <span class="k">for</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">def_ancs</span><span class="p">[</span><span class="n">var_A</span><span class="p">]</span> <span class="k">if</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">lag_A</span> <span class="o">&gt;=</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">})</span>

        <span class="c1"># Return</span>
        <span class="k">return</span> <span class="n">out</span>


    <span class="k">def</span> <span class="nf">_get_non_ancs</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">node_list</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return the currently known set of non-ancestors of all nodes in the list node_list. The nodes are not required to be</span>
<span class="sd">        at lag 0&quot;&quot;&quot;</span>

        <span class="c1"># Build the output set</span>
        <span class="n">out</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>

        <span class="c1"># Run through all nodes</span>
        <span class="k">for</span> <span class="n">A</span> <span class="ow">in</span> <span class="n">node_list</span><span class="p">:</span>
            <span class="c1"># Unpack the node</span>
            <span class="p">(</span><span class="n">var_A</span><span class="p">,</span> <span class="n">lag_A</span><span class="p">)</span> <span class="o">=</span> <span class="n">A</span>
            <span class="c1"># Add the ancestors of node to out</span>
            <span class="n">out</span> <span class="o">=</span> <span class="n">out</span><span class="o">.</span><span class="n">union</span><span class="p">({(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">lag_A</span><span class="p">)</span> <span class="k">for</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">def_non_ancs</span><span class="p">[</span><span class="n">var_A</span><span class="p">]</span> <span class="k">if</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">lag_A</span> <span class="o">&gt;=</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">})</span>

        <span class="c1"># Return</span>
        <span class="k">return</span> <span class="n">out</span>


    <span class="k">def</span> <span class="nf">_fix_all_edges</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Remove all non-trivial orientations&quot;&quot;&quot;</span>

        <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">):</span>
            <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span>

                <span class="n">link</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
                <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">link</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
                    <span class="n">new_link</span> <span class="o">=</span> <span class="n">link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;-&quot;</span> <span class="o">+</span> <span class="n">link</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">j</span><span class="p">][(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)]</span> <span class="o">=</span> <span class="n">new_link</span>

    <span class="c1">########################################################################################################################</span>
    <span class="c1">########################################################################################################################</span>
    <span class="c1">########################################################################################################################</span>

    <span class="k">def</span> <span class="nf">_apply_APR</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">only_lagged</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return all orientations implied by orientation rule APR&quot;&quot;&quot;</span>

        <span class="c1"># Build the output list</span>
        <span class="n">out</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">no_apr</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">out</span>

        <span class="c1"># Get and run through all relevant graphical structures</span>
        <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">):</span>
            <span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">j</span><span class="p">]:</span>

                <span class="n">A</span> <span class="o">=</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span>
                <span class="n">B</span> <span class="o">=</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>

                <span class="k">if</span> <span class="n">only_lagged</span> <span class="ow">and</span> <span class="n">lag_i</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                    <span class="k">continue</span>

                <span class="c1"># Get the link from A to B</span>
                <span class="n">link_AB</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">)</span>

                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_match_link</span><span class="p">(</span><span class="n">pattern</span><span class="o">=</span><span class="s1">&#39;-!&gt;&#39;</span><span class="p">,</span> <span class="n">link</span><span class="o">=</span><span class="n">link_AB</span><span class="p">)</span> \
                   <span class="ow">or</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_match_link</span><span class="p">(</span><span class="n">pattern</span><span class="o">=</span><span class="s1">&#39;-R&gt;&#39;</span><span class="p">,</span> <span class="n">link</span><span class="o">=</span><span class="n">link_AB</span><span class="p">)</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_smaller</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">))</span> \
                   <span class="ow">or</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_match_link</span><span class="p">(</span><span class="n">pattern</span><span class="o">=</span><span class="s1">&#39;-L&gt;&#39;</span><span class="p">,</span> <span class="n">link</span><span class="o">=</span><span class="n">link_AB</span><span class="p">)</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_smaller</span><span class="p">(</span><span class="n">B</span><span class="p">,</span> <span class="n">A</span><span class="p">)):</span>

                    <span class="c1"># Write the new link from A to B to the output list</span>
                    <span class="n">out</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_get_pair_key_and_new_link</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="s2">&quot;--&gt;&quot;</span><span class="p">))</span>

        <span class="c1"># Return the output list</span>
        <span class="k">return</span> <span class="n">out</span>

    <span class="k">def</span> <span class="nf">_apply_ER01</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">only_lagged</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return all orientations implied by orientation rule R1^prime&quot;&quot;&quot;</span>

        <span class="c1"># Build the output list</span>
        <span class="n">out</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="c1"># Find all graphical structures that the rule applies to</span>
        <span class="n">all_appropriate_triples</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_find_triples</span><span class="p">(</span><span class="n">pattern_ij</span><span class="o">=</span><span class="s1">&#39;**&gt;&#39;</span><span class="p">,</span> <span class="n">pattern_jk</span><span class="o">=</span><span class="s1">&#39;o*+&#39;</span><span class="p">,</span> <span class="n">pattern_ik</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">)</span>

        <span class="c1"># Run through all appropriate graphical structures</span>
        <span class="k">for</span> <span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">C</span><span class="p">)</span> <span class="ow">in</span> <span class="n">all_appropriate_triples</span><span class="p">:</span>

            <span class="k">if</span> <span class="n">only_lagged</span> <span class="ow">and</span> <span class="n">B</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
                    <span class="k">continue</span>

            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">:</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ER01: &quot;</span><span class="p">,</span> <span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">C</span><span class="p">))</span>

            <span class="c1"># Check whether the rule applies</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_B_in_SepSet_AC</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">C</span><span class="p">):</span>

                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">:</span>
                    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot; --&gt; in sepset &quot;</span><span class="p">)</span>

                <span class="c1"># Prepare the new link from B to C and append it to the output list</span>
                <span class="n">link_BC</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">B</span><span class="p">,</span> <span class="n">C</span><span class="p">)</span>
                <span class="n">new_link_BC</span> <span class="o">=</span> <span class="s2">&quot;-&quot;</span> <span class="o">+</span> <span class="n">link_BC</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;&gt;&quot;</span>
                <span class="n">out</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_get_pair_key_and_new_link</span><span class="p">(</span><span class="n">B</span><span class="p">,</span> <span class="n">C</span><span class="p">,</span> <span class="n">new_link_BC</span><span class="p">))</span>

        <span class="c1"># Return the output list</span>
        <span class="k">return</span> <span class="n">out</span>

    <span class="k">def</span> <span class="nf">_apply_ER02</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">only_lagged</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return all orientations implied by orientation rule R2^prime&quot;&quot;&quot;</span>

        <span class="c1"># Build the output list</span>
        <span class="n">out</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="c1"># Find all graphical structures that the rule applies to</span>
        <span class="n">all_appropriate_triples</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_find_triples</span><span class="p">(</span><span class="n">pattern_ij</span><span class="o">=</span><span class="s1">&#39;-*&gt;&#39;</span><span class="p">,</span> <span class="n">pattern_jk</span><span class="o">=</span><span class="s1">&#39;**&gt;&#39;</span><span class="p">,</span> <span class="n">pattern_ik</span><span class="o">=</span><span class="s1">&#39;+*o&#39;</span><span class="p">))</span>
        <span class="n">all_appropriate_triples</span> <span class="o">=</span> <span class="n">all_appropriate_triples</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_find_triples</span><span class="p">(</span><span class="n">pattern_ij</span><span class="o">=</span><span class="s1">&#39;**&gt;&#39;</span><span class="p">,</span> <span class="n">pattern_jk</span><span class="o">=</span><span class="s1">&#39;-*&gt;&#39;</span><span class="p">,</span> <span class="n">pattern_ik</span><span class="o">=</span><span class="s1">&#39;+*o&#39;</span><span class="p">)))</span>

        <span class="c1"># Run through all appropriate graphical structures</span>
        <span class="k">for</span> <span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">C</span><span class="p">)</span> <span class="ow">in</span> <span class="n">all_appropriate_triples</span><span class="p">:</span>

            <span class="k">if</span> <span class="n">only_lagged</span> <span class="ow">and</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
                    <span class="k">continue</span>

            <span class="c1"># The rule applies to all relevant graphical structures. Therefore, prepare the new link and append it to the output list</span>
            <span class="n">link_AC</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">)</span>
            <span class="n">new_link_AC</span> <span class="o">=</span> <span class="n">link_AC</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">link_AC</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;&gt;&quot;</span>
            <span class="n">out</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_get_pair_key_and_new_link</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">,</span> <span class="n">new_link_AC</span><span class="p">))</span>

            <span class="c1"># print(&quot;Rule 2&quot;, A, self._get_link(A, B), B, self._get_link(B, C), C, self._get_link(A, C), new_link_AC)</span>

        <span class="c1"># Return the output list</span>
        <span class="k">return</span> <span class="n">out</span>


    <span class="k">def</span> <span class="nf">_apply_ER03</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">only_lagged</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return all orientations implied by orientation rule R3^prime&quot;&quot;&quot;</span>

        <span class="c1"># Build the output list</span>
        <span class="n">out</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="c1"># Find all graphical structures that the rule applies to</span>
        <span class="n">all_appropriate_quadruples</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_find_quadruples</span><span class="p">(</span><span class="n">pattern_ij</span><span class="o">=</span><span class="s1">&#39;**&gt;&#39;</span><span class="p">,</span> <span class="n">pattern_jk</span><span class="o">=</span><span class="s1">&#39;&lt;**&#39;</span><span class="p">,</span> <span class="n">pattern_ik</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">,</span> 
                                                           <span class="n">pattern_il</span><span class="o">=</span><span class="s1">&#39;+*o&#39;</span><span class="p">,</span> <span class="n">pattern_jl</span><span class="o">=</span><span class="s1">&#39;o*+&#39;</span><span class="p">,</span> <span class="n">pattern_kl</span><span class="o">=</span><span class="s1">&#39;+*o&#39;</span><span class="p">)</span>

        <span class="c1"># Run through all appropriate graphical structures</span>
        <span class="k">for</span> <span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">C</span><span class="p">,</span> <span class="n">D</span><span class="p">)</span> <span class="ow">in</span> <span class="n">all_appropriate_quadruples</span><span class="p">:</span>

            <span class="k">if</span> <span class="n">only_lagged</span> <span class="ow">and</span> <span class="n">B</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">D</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
                <span class="k">continue</span>

            <span class="c1"># Check whether the rule applies</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_B_in_SepSet_AC</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">D</span><span class="p">,</span> <span class="n">C</span><span class="p">):</span>

                <span class="c1"># Prepare the new link from D to B and append it to the output list</span>
                <span class="n">link_DB</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">D</span><span class="p">,</span> <span class="n">B</span><span class="p">)</span>
                <span class="n">new_link_DB</span> <span class="o">=</span> <span class="n">link_DB</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">link_DB</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;&gt;&quot;</span>
                <span class="n">out</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_get_pair_key_and_new_link</span><span class="p">(</span><span class="n">D</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">new_link_DB</span><span class="p">))</span>

        <span class="c1"># Return the output list</span>
        <span class="k">return</span> <span class="n">out</span>


    <span class="k">def</span> <span class="nf">_apply_R04</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">only_lagged</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return all orientations implied by orientation rule R4 (standard FCI rule)&quot;&quot;&quot;</span>

        <span class="c1"># Build the output list</span>
        <span class="n">out</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="c1"># Find all relevant triangles W-V-Y</span>
        <span class="n">all_appropriate_triples</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_find_triples</span><span class="p">(</span><span class="n">pattern_ij</span><span class="o">=</span><span class="s1">&#39;&lt;-*&#39;</span><span class="p">,</span> <span class="n">pattern_jk</span><span class="o">=</span><span class="s1">&#39;o-+&#39;</span><span class="p">,</span> <span class="n">pattern_ik</span><span class="o">=</span><span class="s1">&#39;--&gt;&#39;</span><span class="p">)</span>

        <span class="c1"># Run through all of these triangles</span>
        <span class="k">for</span> <span class="n">triple</span> <span class="ow">in</span> <span class="n">all_appropriate_triples</span><span class="p">:</span>

            <span class="p">(</span><span class="n">W</span><span class="p">,</span> <span class="n">V</span><span class="p">,</span> <span class="n">Y</span><span class="p">)</span> <span class="o">=</span> <span class="n">triple</span>

            <span class="k">if</span> <span class="n">only_lagged</span> <span class="ow">and</span> <span class="p">(</span><span class="n">V</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">Y</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="ow">and</span> <span class="n">W</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">V</span><span class="p">[</span><span class="mi">1</span><span class="p">]):</span>
                <span class="k">continue</span>

            <span class="c1"># Get the current link from W to V, which we will need below</span>
            <span class="n">link_WV</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">W</span><span class="p">,</span> <span class="n">V</span><span class="p">)</span>

            <span class="c1"># Find all discriminating paths for this triangle</span>
            <span class="c1"># Note: To guarantee order independence, we check all discriminating paths. Alternatively, we could check the rule for all</span>
            <span class="c1"># shortest such paths</span>
            <span class="n">discriminating_paths</span> <span class="o">=</span>  <span class="bp">self</span><span class="o">.</span><span class="n">_get_R4_discriminating_paths</span><span class="p">(</span><span class="n">triple</span><span class="p">,</span> <span class="n">max_length</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">inf</span><span class="p">)</span>

            <span class="c1"># Run through all discriminating paths</span>
            <span class="k">for</span> <span class="n">path</span> <span class="ow">in</span> <span class="n">discriminating_paths</span><span class="p">:</span>

                <span class="c1"># Get the end point node</span>
                <span class="n">X_1</span> <span class="o">=</span> <span class="n">path</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>

                <span class="c1"># Check which of the two cases of the rule we are in, then append the appropriate new links to the output list</span>
                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_B_in_SepSet_AC</span><span class="p">(</span><span class="n">X_1</span><span class="p">,</span> <span class="n">V</span><span class="p">,</span> <span class="n">Y</span><span class="p">):</span>
                    <span class="c1"># New link from V to Y</span>
                    <span class="n">out</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_get_pair_key_and_new_link</span><span class="p">(</span><span class="n">V</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="s2">&quot;--&gt;&quot;</span><span class="p">))</span>

                <span class="k">elif</span> <span class="n">link_WV</span> <span class="o">!=</span> <span class="s2">&quot;&lt;-x&quot;</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_B_not_in_SepSet_AC</span><span class="p">(</span><span class="n">X_1</span><span class="p">,</span> <span class="n">V</span><span class="p">,</span> <span class="n">Y</span><span class="p">):</span>
                    <span class="c1"># New link from V to Y</span>
                    <span class="n">out</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_get_pair_key_and_new_link</span><span class="p">(</span><span class="n">V</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="s2">&quot;&lt;-&gt;&quot;</span><span class="p">))</span>

                    <span class="c1"># If needed, also the new link from W to V</span>
                    <span class="k">if</span> <span class="n">link_WV</span> <span class="o">!=</span> <span class="s2">&quot;&lt;-&gt;&quot;</span><span class="p">:</span>
                        <span class="n">out</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_get_pair_key_and_new_link</span><span class="p">(</span><span class="n">W</span><span class="p">,</span> <span class="n">V</span><span class="p">,</span> <span class="s2">&quot;&lt;-&gt;&quot;</span><span class="p">))</span>

        <span class="c1"># Return the output list</span>
        <span class="k">return</span> <span class="n">out</span>


    <span class="k">def</span> <span class="nf">_apply_ER08</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">only_lagged</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return all orientations implied by orientation rule R8^prime&quot;&quot;&quot;</span>

        <span class="c1"># Build the output list</span>
        <span class="n">out</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="c1"># Find all graphical structures that the rule applies to</span>
        <span class="n">all_appropriate_triples</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_find_triples</span><span class="p">(</span><span class="n">pattern_ij</span><span class="o">=</span><span class="s1">&#39;-*&gt;&#39;</span><span class="p">,</span> <span class="n">pattern_jk</span><span class="o">=</span><span class="s1">&#39;-*&gt;&#39;</span><span class="p">,</span> <span class="n">pattern_ik</span><span class="o">=</span><span class="s1">&#39;o*+&#39;</span><span class="p">)</span>

        <span class="c1"># Run through all appropriate graphical structures</span>
        <span class="k">for</span> <span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">C</span><span class="p">)</span> <span class="ow">in</span> <span class="n">all_appropriate_triples</span><span class="p">:</span>

            <span class="k">if</span> <span class="n">only_lagged</span> <span class="ow">and</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
                <span class="k">continue</span>

            <span class="c1"># The rule applies to all relevant graphical structures. Therefore, prepare the new link and append it to the output list</span>
            <span class="n">link_AC</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">)</span>
            <span class="n">new_link_AC</span> <span class="o">=</span> <span class="s2">&quot;-&quot;</span> <span class="o">+</span> <span class="n">link_AC</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;&gt;&quot;</span>
            <span class="n">out</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_get_pair_key_and_new_link</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">,</span> <span class="n">new_link_AC</span><span class="p">))</span>

            <span class="c1">#print(&quot;Rule 8:&quot;, A, self._get_link(A, B), B, self._get_link(B, C), C, link_AC, new_link_AC)</span>

        <span class="c1"># Return the output list</span>
        <span class="k">return</span> <span class="n">out</span>


    <span class="k">def</span> <span class="nf">_apply_ER09</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">only_lagged</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return all orientations implied by orientation rule R9^prime&quot;&quot;&quot;</span>

        <span class="c1"># Build the output list</span>
        <span class="n">out</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="c1"># Find unshielded triples B_1 o--*--o A o--*--&gt; C or B_1 &lt;--*--o A o--*--&gt; C or B_1 &lt;--*-- A o--*--&gt; C </span>
        <span class="n">all_appropriate_triples</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_find_triples</span><span class="p">(</span><span class="n">pattern_ij</span><span class="o">=</span><span class="s1">&#39;o*o&#39;</span><span class="p">,</span> <span class="n">pattern_jk</span><span class="o">=</span><span class="s1">&#39;o*&gt;&#39;</span><span class="p">,</span> <span class="n">pattern_ik</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">))</span>
        <span class="n">all_appropriate_triples</span> <span class="o">=</span> <span class="n">all_appropriate_triples</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_find_triples</span><span class="p">(</span><span class="n">pattern_ij</span><span class="o">=</span><span class="s1">&#39;&lt;*o&#39;</span><span class="p">,</span> <span class="n">pattern_jk</span><span class="o">=</span><span class="s1">&#39;o*&gt;&#39;</span><span class="p">,</span> <span class="n">pattern_ik</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">)))</span>
        <span class="n">all_appropriate_triples</span> <span class="o">=</span> <span class="n">all_appropriate_triples</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_find_triples</span><span class="p">(</span><span class="n">pattern_ij</span><span class="o">=</span><span class="s1">&#39;&lt;*-&#39;</span><span class="p">,</span> <span class="n">pattern_jk</span><span class="o">=</span><span class="s1">&#39;o*&gt;&#39;</span><span class="p">,</span> <span class="n">pattern_ik</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">)))</span>

        <span class="c1"># Run through all these triples</span>
        <span class="k">for</span> <span class="p">(</span><span class="n">B_1</span><span class="p">,</span> <span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">)</span> <span class="ow">in</span> <span class="n">all_appropriate_triples</span><span class="p">:</span>

            <span class="k">if</span> <span class="n">only_lagged</span> <span class="ow">and</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
                <span class="k">continue</span>

            <span class="c1"># Check whether A is in SepSet(B_1, C), else the rule does not apply</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_B_in_SepSet_AC</span><span class="p">(</span><span class="n">B_1</span><span class="p">,</span> <span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">):</span>
                <span class="k">continue</span>

            <span class="c1"># Although we do not yet know whether the rule applies, we here determine the new form of the link from A to C if the rule</span>
            <span class="c1"># does apply</span>
            <span class="n">link_AC</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">)</span>
            <span class="n">new_link_AC</span> <span class="o">=</span> <span class="s2">&quot;-&quot;</span> <span class="o">+</span> <span class="n">link_AC</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;&gt;&quot;</span>
            <span class="n">pair_key</span><span class="p">,</span> <span class="n">new_link</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_pair_key_and_new_link</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">,</span> <span class="n">new_link_AC</span><span class="p">)</span>

            <span class="c1"># For the search of uncovered potentially directed paths from B_1 to C, determine the initial pattern as dictated by the link</span>
            <span class="c1"># from A to B_1</span>
            <span class="n">first_link</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B_1</span><span class="p">)</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_match_link</span><span class="p">(</span><span class="n">pattern</span><span class="o">=</span><span class="s1">&#39;o*o&#39;</span><span class="p">,</span> <span class="n">link</span><span class="o">=</span><span class="n">first_link</span><span class="p">):</span>
                <span class="n">initial_allowed_patterns</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;-*&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;o*&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;o*o&#39;</span><span class="p">]</span>
            <span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">_match_link</span><span class="p">(</span><span class="n">pattern</span><span class="o">=</span><span class="s1">&#39;o*&gt;&#39;</span><span class="p">,</span> <span class="n">link</span><span class="o">=</span><span class="n">first_link</span><span class="p">)</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_match_link</span><span class="p">(</span><span class="n">pattern</span><span class="o">=</span><span class="s1">&#39;-*&gt;&#39;</span><span class="p">,</span> <span class="n">link</span><span class="o">=</span><span class="n">first_link</span><span class="p">):</span>
                <span class="n">initial_allowed_patterns</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;-*&gt;&#39;</span><span class="p">]</span>
            
            <span class="c1"># Return all uncovered potentially directed paths from B_1 to C</span>
            <span class="c1">#uncovered_pd_paths =  self._find_potentially_directed_paths(B_1, C, initial_allowed_patterns, return_if_any_path_found = False,</span>
            <span class="c1"># uncovered=True, reduce_allowed_patterns=True, max_length = np.inf)</span>

            <span class="c1"># Find all uncovered potentially directed paths from B_1 to C</span>
            <span class="n">uncovered_pd_paths</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_potentially_directed_uncovered_paths</span><span class="p">(</span><span class="n">B_1</span><span class="p">,</span> <span class="n">C</span><span class="p">,</span> <span class="n">initial_allowed_patterns</span><span class="p">)</span>

            <span class="c1"># Run through all of these paths and check i) whether the node adjacent to B_1 is non-adjacent to A, ii) whether condition iv) of</span>
            <span class="c1"># the rule antecedent is true. If there is any such path, then the link can be oriented</span>
            <span class="k">for</span> <span class="n">upd_path</span> <span class="ow">in</span> <span class="n">uncovered_pd_paths</span><span class="p">:</span>

                <span class="c1"># Is the node adjacent to B_1 non-adjacent to A (this implies that there are at least three nodes on the path, because else the</span>
                <span class="c1"># node adjacent to B_1 is C) and is A not part of the path?</span>
                <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">upd_path</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">3</span> <span class="ow">or</span> <span class="n">A</span> <span class="ow">in</span> <span class="n">upd_path</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">upd_path</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">!=</span> <span class="s2">&quot;&quot;</span><span class="p">:</span>
                    <span class="k">continue</span>

                <span class="c1"># If the link from A to B_1 is into B_1, condition iv) is true</span>
                <span class="k">if</span> <span class="n">first_link</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;&gt;&quot;</span><span class="p">:</span>
                    <span class="c1"># Mark the link from A to C for orientation, break the for loop to continue with the next triple</span>
                    <span class="n">out</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">pair_key</span><span class="p">,</span> <span class="n">new_link</span><span class="p">))</span>
                    <span class="k">break</span>

                <span class="c1"># If the link from A to B_1 is not in B_1, we need to check whether B_1 is in SepSet(A, X) where X is the node on upd_path next</span>
                <span class="c1"># to B_1</span>
                <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_B_in_SepSet_AC</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B_1</span><span class="p">,</span> <span class="n">upd_path</span><span class="p">[</span><span class="mi">1</span><span class="p">]):</span>
                    <span class="c1"># Continue with the next upd_path</span>
                    <span class="k">continue</span>

                <span class="c1"># Now check whether rule iv) for all triples on upd_path</span>
                <span class="n">path_qualifies</span> <span class="o">=</span> <span class="kc">True</span>
                <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">upd_path</span><span class="p">)</span> <span class="o">-</span> <span class="mi">2</span><span class="p">):</span>
                    <span class="c1"># We consider the unshielded triples upd_path[i] - upd_path[i+1] - upd_path[i+2]</span>

                    <span class="c1"># If the link between upd_path[i] and upd_path[i+1] is into the latter, condition iv) is true</span>
                    <span class="n">left_link</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">upd_path</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">upd_path</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">])</span>
                    <span class="k">if</span> <span class="n">left_link</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;&gt;&quot;</span><span class="p">:</span>
                        <span class="c1"># The path qualifies, break the inner for loop</span>
                        <span class="k">break</span>

                    <span class="c1"># If not, then we need to continue with checking whether upd_path[i+1] in SepSet(upd_path[i+1], upd_path[i+2])</span>
                    <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_B_in_SepSet_AC</span><span class="p">(</span><span class="n">upd_path</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">upd_path</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">],</span> <span class="n">upd_path</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="mi">2</span><span class="p">]):</span>
                        <span class="c1"># The path does not qualifying, break the inner for loop</span>
                        <span class="n">path_qualifies</span> <span class="o">=</span> <span class="kc">False</span>
                        <span class="k">break</span>

                <span class="c1"># The path qualifies, mark the edge from A to C for orientation and break the outer for loop to continue with the next triple</span>
                <span class="k">if</span> <span class="n">path_qualifies</span><span class="p">:</span>
                    <span class="n">out</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">pair_key</span><span class="p">,</span> <span class="n">new_link</span><span class="p">))</span>
                    <span class="k">break</span>

                <span class="c1"># The path does not qualify, continue with the next upd_path</span>

            <span class="c1"># end for upd_path in uncovered_pd_paths</span>
        <span class="c1"># end for (B_1, A, C) in all_appropriate_triples</span>

        <span class="c1"># Return the output list</span>
        <span class="k">return</span> <span class="n">out</span>


    <span class="k">def</span> <span class="nf">_apply_ER10</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">only_lagged</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return all orientations implied by orientation rule R10^prime&quot;&quot;&quot;</span>

        <span class="c1"># Build the output list</span>
        <span class="n">out</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="c1"># Find all triples A o--&gt; C &lt;-- P_C</span>
        <span class="n">all_appropriate_triples</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_find_triples</span><span class="p">(</span><span class="n">pattern_ij</span><span class="o">=</span><span class="s1">&#39;o*&gt;&#39;</span><span class="p">,</span> <span class="n">pattern_jk</span><span class="o">=</span><span class="s1">&#39;&lt;*-&#39;</span><span class="p">,</span> <span class="n">pattern_ik</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">))</span>
        <span class="n">all_appropriate_triples</span> <span class="o">=</span> <span class="n">all_appropriate_triples</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_find_triples</span><span class="p">(</span><span class="n">pattern_ij</span><span class="o">=</span><span class="s1">&#39;o*&gt;&#39;</span><span class="p">,</span> <span class="n">pattern_jk</span><span class="o">=</span><span class="s1">&#39;&lt;*-&#39;</span><span class="p">,</span> <span class="n">pattern_ik</span><span class="o">=</span><span class="s1">&#39;***&#39;</span><span class="p">)))</span>

        <span class="c1"># Collect all triples for the given pair (A, C)</span>
        <span class="n">triple_sorting_dict</span> <span class="o">=</span> <span class="p">{}</span>
        <span class="k">for</span> <span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">,</span> <span class="n">P_C</span><span class="p">)</span> <span class="ow">in</span> <span class="n">all_appropriate_triples</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">triple_sorting_dict</span><span class="o">.</span><span class="n">get</span><span class="p">((</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">))</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
                <span class="n">triple_sorting_dict</span><span class="p">[(</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">)]</span> <span class="o">=</span> <span class="p">[</span><span class="n">P_C</span><span class="p">]</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">triple_sorting_dict</span><span class="p">[(</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">)]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">P_C</span><span class="p">)</span>


        <span class="c1"># Run through all (A, C) pairs</span>
        <span class="k">for</span> <span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">)</span> <span class="ow">in</span> <span class="n">triple_sorting_dict</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span>

            <span class="k">if</span> <span class="n">only_lagged</span> <span class="ow">and</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
                <span class="k">continue</span>

            <span class="c1"># Find all uncovered potentially directed paths from A to C through any of the P_C nodes</span>
            <span class="n">relevant_paths</span> <span class="o">=</span> <span class="p">[]</span>
            <span class="k">for</span> <span class="n">P_C</span> <span class="ow">in</span> <span class="n">triple_sorting_dict</span><span class="p">[(</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">)]:</span>
                <span class="k">for</span> <span class="n">upd_path</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_potentially_directed_uncovered_paths</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">P_C</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;-*&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;o*&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;o*o&#39;</span><span class="p">]):</span>

                    <span class="c1"># Run through all of these paths and check i) whether the second to last element is not adjacent to C (this requires it to</span>
                    <span class="c1"># have a least three nodes, because else the second to last element would be A) and ii) whether the left edge of any 3-node</span>
                    <span class="c1"># sub-path is into the middle nor or, if not, whether the middle node is in the separating set of the two end-point nodes</span>
                    <span class="c1"># (of the 3-node) sub-path and iii) whether C is not element of the path. If path meets these conditions, add its second node</span>
                    <span class="c1"># (the adjacent to A) to the set second_nodes</span>

                    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">upd_path</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">3</span> <span class="ow">or</span> <span class="n">C</span> <span class="ow">in</span> <span class="n">upd_path</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">upd_path</span><span class="p">[</span><span class="o">-</span><span class="mi">2</span><span class="p">],</span> <span class="n">C</span><span class="p">)</span> <span class="o">!=</span> <span class="s2">&quot;&quot;</span><span class="p">:</span>
                        <span class="k">continue</span>

                    <span class="n">upd_path</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">C</span><span class="p">)</span>

                    <span class="n">path_qualifies</span> <span class="o">=</span> <span class="kc">True</span>
                    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">upd_path</span><span class="p">)</span> <span class="o">-</span> <span class="mi">2</span><span class="p">):</span>
                        <span class="c1"># We consider the unshielded triples upd_path[i] - upd_path[i+1] - upd_path[i+2]</span>

                        <span class="c1"># If the link between upd_path[i] and upd_path[i+1] is into the latter, the path qualifies</span>
                        <span class="n">left_link</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">upd_path</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">upd_path</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">])</span>
                        <span class="k">if</span> <span class="n">left_link</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;&gt;&quot;</span><span class="p">:</span>
                            <span class="c1"># The path qualifies, break the inner for loop</span>
                            <span class="k">break</span>

                        <span class="c1"># If not, then we need to continue with checking whether upd_path[i+1] in SepSet(upd_path[i+1], upd_path[i+2])</span>
                        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_B_in_SepSet_AC</span><span class="p">(</span><span class="n">upd_path</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">upd_path</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">],</span> <span class="n">upd_path</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="mi">2</span><span class="p">]):</span>
                            <span class="c1"># The path does not qualify, break the inner for loop</span>
                            <span class="n">path_qualifies</span> <span class="o">=</span> <span class="kc">False</span>
                            <span class="k">break</span>

                    <span class="c1"># The path qualifies, add upd_path[i] to second_nodes and continue with the next upd_path</span>
                    <span class="k">if</span> <span class="n">path_qualifies</span><span class="p">:</span>
                        <span class="n">relevant_paths</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">upd_path</span><span class="p">)</span>

                <span class="c1"># The path does not qualify, continue with the next upd_path</span>

                <span class="c1"># end for path in self._get_potentially_directed_uncovered_paths(A, P_C, [&#39;-*&gt;&#39;, &#39;o*&gt;&#39;, &#39;o*o&#39;])</span>
            <span class="c1"># end for P_C in triple_sorting_dict[(A, C)]</span>

            <span class="c1"># Find all second nodes on the relevant paths</span>
            <span class="n">second_nodes</span> <span class="o">=</span> <span class="nb">list</span><span class="p">({</span><span class="n">path</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">for</span> <span class="n">path</span> <span class="ow">in</span> <span class="n">relevant_paths</span><span class="p">})</span>

            <span class="c1"># Check whether there is any pair of non-adjacent nodes in second_nodes, such that A is in their separating set. If yes, mark the link</span>
            <span class="c1"># from A to C for orientation</span>
            <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">j</span> <span class="ow">in</span> <span class="n">product</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">second_nodes</span><span class="p">)),</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">second_nodes</span><span class="p">))):</span>

                <span class="k">if</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">j</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">second_nodes</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">second_nodes</span><span class="p">[</span><span class="n">j</span><span class="p">])</span> <span class="o">==</span> <span class="s2">&quot;&quot;</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_B_in_SepSet_AC</span><span class="p">(</span><span class="n">second_nodes</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">A</span><span class="p">,</span> <span class="n">second_nodes</span><span class="p">[</span><span class="n">j</span><span class="p">]):</span>
                    <span class="c1"># Append new link and break the for loop</span>
                    <span class="n">link_AC</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">)</span>
                    <span class="n">new_link_AC</span> <span class="o">=</span> <span class="s2">&quot;-&quot;</span> <span class="o">+</span> <span class="n">link_AC</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;&gt;&quot;</span>
                    <span class="n">out</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_get_pair_key_and_new_link</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">,</span> <span class="n">new_link_AC</span><span class="p">))</span>
                    <span class="k">break</span>

        <span class="c1"># end for (A, C) in triple_sorting_dict.keys()</span>

        <span class="c1"># Return the output list</span>
        <span class="k">return</span> <span class="n">out</span>


    <span class="k">def</span> <span class="nf">_apply_ER00a</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">only_lagged</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return all orientations implied by orientation rule R0^prime a&quot;&quot;&quot;</span>

        <span class="c1"># Build the output list</span>
        <span class="n">out</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="c1"># Find all graphical structures that the rule applies to</span>
        <span class="n">all_appropriate_triples</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_find_triples</span><span class="p">(</span><span class="n">pattern_ij</span><span class="o">=</span><span class="s1">&#39;***&#39;</span><span class="p">,</span> <span class="n">pattern_jk</span><span class="o">=</span><span class="s1">&#39;***&#39;</span><span class="p">,</span> <span class="n">pattern_ik</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">)</span>

        <span class="c1"># Run through all appropriate graphical structures</span>
        <span class="k">for</span> <span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">C</span><span class="p">)</span> <span class="ow">in</span> <span class="n">all_appropriate_triples</span><span class="p">:</span>

            <span class="c1"># Unpack A, B, C</span>
            <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="o">=</span> <span class="n">A</span>
            <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="n">lag_j</span><span class="p">)</span> <span class="o">=</span> <span class="n">B</span>
            <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">lag_k</span><span class="p">)</span> <span class="o">=</span> <span class="n">C</span>

            <span class="k">if</span> <span class="n">only_lagged</span> <span class="ow">and</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">B</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="ow">or</span> <span class="n">B</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">]):</span>
                <span class="k">continue</span>

            <span class="c1"># Get all weakly minimal separating sets in SepSet(A, C)</span>
            <span class="c1"># Remark: The non weakly minimal separating sets may be larger, that&#39;s why we disfavor them</span>
            <span class="n">sepsets</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_sepsets</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">)</span>
            <span class="n">sepsets</span> <span class="o">=</span> <span class="p">{</span><span class="n">Z</span> <span class="k">for</span> <span class="p">(</span><span class="n">Z</span><span class="p">,</span> <span class="n">status</span><span class="p">)</span> <span class="ow">in</span> <span class="n">sepsets</span> <span class="k">if</span> <span class="n">status</span> <span class="o">==</span> <span class="s2">&quot;wm&quot;</span><span class="p">}</span>

            <span class="c1">###################################################################################</span>
            <span class="c1">### Part 1) of the rule ###########################################################</span>

            <span class="n">remove_AB</span> <span class="o">=</span> <span class="kc">False</span>
            <span class="n">link_AB</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">)</span>

            <span class="c1"># i) Middle mark must not be &quot;x&quot; or &quot;-&quot;</span>
            <span class="k">if</span> <span class="n">link_AB</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="s1">&#39;-&#39;</span><span class="p">,</span> <span class="s1">&#39;x&#39;</span><span class="p">]:</span>
                <span class="c1"># Test A indep B given union(SepSet(A, C), intersection(def-anc(B), adj(B))) setminus{A, B} setminus{future of both A and B}</span>

                <span class="c1"># Conditioning on parents</span>
                <span class="n">Z_add</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_parents</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">)</span><span class="o">.</span><span class="n">difference</span><span class="p">({</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">})</span>

                <span class="c1"># Shift the lags appropriately</span>
                <span class="k">if</span> <span class="n">lag_i</span> <span class="o">&lt;=</span> <span class="n">lag_j</span><span class="p">:</span>
                    <span class="n">X</span> <span class="o">=</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span> <span class="o">-</span> <span class="n">lag_j</span><span class="p">)</span> <span class="c1"># A shifted</span>
                    <span class="n">Y</span> <span class="o">=</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="c1"># B shifted</span>
                    <span class="n">delta_lag</span> <span class="o">=</span> <span class="n">lag_j</span>

                <span class="k">else</span><span class="p">:</span>
                    <span class="n">X</span> <span class="o">=</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="n">lag_j</span> <span class="o">-</span> <span class="n">lag_i</span><span class="p">)</span> <span class="c1"># B shifted</span>
                    <span class="n">Y</span> <span class="o">=</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="c1"># A shifted</span>
                    <span class="n">delta_lag</span> <span class="o">=</span> <span class="n">lag_i</span>

                <span class="c1"># Run through all weakly minimal separating sets of A and C</span>
                <span class="k">for</span> <span class="n">Z</span> <span class="ow">in</span> <span class="n">sepsets</span><span class="p">:</span>      

                    <span class="c1"># Construct the conditioning set to test</span>
                    <span class="n">Z_test</span> <span class="o">=</span> <span class="n">Z</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="n">Z_add</span><span class="p">)</span><span class="o">.</span><span class="n">difference</span><span class="p">({</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">})</span>
                    <span class="n">Z_test</span> <span class="o">=</span> <span class="p">{(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">-</span> <span class="n">delta_lag</span><span class="p">)</span> <span class="k">for</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">)</span> <span class="ow">in</span> <span class="n">Z_test</span> <span class="k">if</span> <span class="n">lag</span> <span class="o">-</span> <span class="n">delta_lag</span> <span class="o">&lt;=</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">lag</span> <span class="o">-</span> <span class="n">delta_lag</span> <span class="o">&gt;=</span> <span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">}</span>
                    <span class="n">Z_add2</span> <span class="o">=</span> <span class="p">{(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">-</span> <span class="n">delta_lag</span><span class="p">)</span> <span class="k">for</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">)</span> <span class="ow">in</span> <span class="n">Z_add</span><span class="o">.</span><span class="n">difference</span><span class="p">({</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">})</span> <span class="k">if</span> <span class="n">lag</span> <span class="o">-</span> <span class="n">delta_lag</span> <span class="o">&lt;=</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">lag</span> <span class="o">-</span> <span class="n">delta_lag</span> <span class="o">&gt;=</span> <span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">}</span>

                    <span class="c1"># Test conditional independence of X and Y given Z</span>
                    <span class="c1"># val, pval = self.cond_ind_test.run_test(X = [X], Y = [Y], Z = list(Z_test), tau_max = self.tau_max)</span>
                    <span class="n">val</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">dependent</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cond_ind_test</span><span class="o">.</span><span class="n">run_test</span><span class="p">(</span><span class="n">X</span> <span class="o">=</span> <span class="p">[</span><span class="n">X</span><span class="p">],</span> <span class="n">Y</span> <span class="o">=</span> <span class="p">[</span><span class="n">Y</span><span class="p">],</span> <span class="n">Z</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">Z_test</span><span class="p">),</span> 
                        <span class="n">tau_max</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">,</span> <span class="n">alpha_or_thres</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">pc_alpha</span><span class="p">)</span>

                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">:</span>
                        <span class="c1"># print(&quot;ER00a(part1):    %s _|_ %s  |  Z_test = %s: val = %.2f / pval = % .4f&quot; %</span>
                        <span class="c1">#     (X, Y, &#39; &#39;.join([str(z) for z in list(Z_test)]), val, pval))</span>
                        <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ER00a(part1):    </span><span class="si">%s</span><span class="s2"> _|_ </span><span class="si">%s</span><span class="s2">  |  Z_add = </span><span class="si">%s</span><span class="s2">, Z = </span><span class="si">%s</span><span class="s2">: val = </span><span class="si">%.2f</span><span class="s2"> / pval = </span><span class="si">% .4f</span><span class="s2">&quot;</span> <span class="o">%</span>
                            <span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="n">Z_add2</span><span class="p">]),</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="n">Z_test</span><span class="p">]),</span> <span class="n">val</span><span class="p">,</span> <span class="n">pval</span><span class="p">))</span>

                    <span class="c1"># Accordingly update dictionaries that keep track of the maximal p-value and the corresponding test statistic values and</span>
                    <span class="c1"># conditioning set cardinalities</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_update_pval_val_card_dicts</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">val</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">Z_test</span><span class="p">))</span>

                    <span class="c1"># Check whether test result was significant</span>
                    <span class="k">if</span> <span class="ow">not</span> <span class="n">dependent</span><span class="p">:</span> <span class="c1"># pval &gt; self.pc_alpha:</span>

                        <span class="c1"># Mark the edge from X to Y for removal and save sepset</span>
                        <span class="n">remove_AB</span> <span class="o">=</span> <span class="kc">True</span>
                        <span class="bp">self</span><span class="o">.</span><span class="n">_save_sepset</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="p">(</span><span class="nb">frozenset</span><span class="p">(</span><span class="n">Z_test</span><span class="p">),</span> <span class="s2">&quot;nwm&quot;</span><span class="p">))</span>

                <span class="k">if</span> <span class="n">remove_AB</span><span class="p">:</span>

                    <span class="c1"># Remember the edge for removal</span>
                    <span class="n">pair_key</span><span class="p">,</span> <span class="n">new_link</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_pair_key_and_new_link</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">)</span>
                    <span class="n">out</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">pair_key</span><span class="p">,</span> <span class="n">new_link</span><span class="p">))</span>

            <span class="c1">###################################################################################</span>
            <span class="c1">### Part 2) of the rule ###########################################################</span>

            <span class="n">remove_CB</span> <span class="o">=</span> <span class="kc">False</span>
            <span class="n">link_CB</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">C</span><span class="p">,</span> <span class="n">B</span><span class="p">)</span>

            <span class="c1"># i) Middle mark must not be &quot;x&quot; or &quot;-&quot;</span>
            <span class="k">if</span> <span class="n">link_CB</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="s1">&#39;-&#39;</span><span class="p">,</span> <span class="s1">&#39;x&#39;</span><span class="p">]:</span>
                <span class="c1"># Test C indep B given union(SepSet(A, C), intersection(def-anc(B), adj(B))) setminus{A, B} setminus{future of both C and B}</span>

                <span class="c1"># Conditioning on parents</span>
                <span class="n">Z_add</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_parents</span><span class="p">(</span><span class="n">C</span><span class="p">,</span> <span class="n">B</span><span class="p">)</span><span class="o">.</span><span class="n">difference</span><span class="p">({</span><span class="n">C</span><span class="p">,</span> <span class="n">B</span><span class="p">})</span>

                <span class="c1"># Shift the lags appropriately</span>
                <span class="k">if</span> <span class="n">lag_k</span> <span class="o">&lt;=</span> <span class="n">lag_j</span><span class="p">:</span>
                    <span class="n">X</span> <span class="o">=</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">lag_k</span> <span class="o">-</span> <span class="n">lag_j</span><span class="p">)</span>
                    <span class="n">Y</span> <span class="o">=</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
                    <span class="n">delta_lag</span> <span class="o">=</span> <span class="n">lag_j</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="n">X</span> <span class="o">=</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="n">lag_j</span> <span class="o">-</span> <span class="n">lag_k</span><span class="p">)</span>
                    <span class="n">Y</span> <span class="o">=</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
                    <span class="n">delta_lag</span> <span class="o">=</span> <span class="n">lag_k</span>

                <span class="c1"># Run through all weakly minimal separating sets of A and C</span>
                <span class="k">for</span> <span class="n">Z</span> <span class="ow">in</span> <span class="n">sepsets</span><span class="p">:</span>

                    <span class="c1"># Construct the conditioning set to test</span>
                    <span class="n">Z_test</span> <span class="o">=</span> <span class="n">Z</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="n">Z_add</span><span class="p">)</span><span class="o">.</span><span class="n">difference</span><span class="p">({</span><span class="n">C</span><span class="p">,</span> <span class="n">B</span><span class="p">})</span>
                    <span class="n">Z_test</span> <span class="o">=</span> <span class="p">{(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">-</span> <span class="n">delta_lag</span><span class="p">)</span> <span class="k">for</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">)</span> <span class="ow">in</span> <span class="n">Z_test</span> <span class="k">if</span> <span class="n">lag</span> <span class="o">-</span> <span class="n">delta_lag</span> <span class="o">&lt;=</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">lag</span> <span class="o">-</span> <span class="n">delta_lag</span> <span class="o">&gt;=</span> <span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">}</span>
                    <span class="n">Z_add2</span> <span class="o">=</span> <span class="p">{(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">-</span> <span class="n">delta_lag</span><span class="p">)</span> <span class="k">for</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">)</span> <span class="ow">in</span> <span class="n">Z_add</span><span class="o">.</span><span class="n">difference</span><span class="p">({</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">})</span> <span class="k">if</span> <span class="n">lag</span> <span class="o">-</span> <span class="n">delta_lag</span> <span class="o">&lt;=</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">lag</span> <span class="o">-</span> <span class="n">delta_lag</span> <span class="o">&gt;=</span> <span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">}</span>

                    <span class="c1"># Test conditional independence of X and Y given Z</span>
                    <span class="c1"># val, pval = self.cond_ind_test.run_test(X = [X], Y = [Y], Z = list(Z_test), tau_max = self.tau_max)</span>
                    <span class="n">val</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">dependent</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cond_ind_test</span><span class="o">.</span><span class="n">run_test</span><span class="p">(</span><span class="n">X</span> <span class="o">=</span> <span class="p">[</span><span class="n">X</span><span class="p">],</span> <span class="n">Y</span> <span class="o">=</span> <span class="p">[</span><span class="n">Y</span><span class="p">],</span> <span class="n">Z</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">Z_test</span><span class="p">),</span> 
                        <span class="n">tau_max</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">,</span> <span class="n">alpha_or_thres</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">pc_alpha</span><span class="p">)</span>

                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">:</span>
                        <span class="c1"># print(&quot;ER00a(part2):    %s _|_ %s  |  Z_test = %s: val = %.2f / pval = % .4f&quot; %</span>
                        <span class="c1">#     (X, Y, &#39; &#39;.join([str(z) for z in list(Z_test)]), val, pval))</span>
                        <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ER00a(part2):    </span><span class="si">%s</span><span class="s2"> _|_ </span><span class="si">%s</span><span class="s2">  |  Z_add = </span><span class="si">%s</span><span class="s2">, Z = </span><span class="si">%s</span><span class="s2">: val = </span><span class="si">%.2f</span><span class="s2"> / pval = </span><span class="si">% .4f</span><span class="s2">&quot;</span> <span class="o">%</span>
                            <span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="n">Z_add2</span><span class="p">]),</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="n">Z_test</span><span class="p">]),</span> <span class="n">val</span><span class="p">,</span> <span class="n">pval</span><span class="p">))</span>

                    <span class="c1"># Accordingly update dictionaries that keep track of the maximal p-value and the corresponding test statistic values and</span>
                    <span class="c1"># conditioning set cardinalities</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_update_pval_val_card_dicts</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">val</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">Z_test</span><span class="p">))</span>

                    <span class="c1"># Check whether test result was significant</span>
                    <span class="k">if</span> <span class="ow">not</span> <span class="n">dependent</span><span class="p">:</span> <span class="c1"># pval &gt; self.pc_alpha:</span>
                        
                        <span class="c1"># Mark the edge from X to Y for removal and save sepset</span>
                        <span class="n">remove_CB</span> <span class="o">=</span> <span class="kc">True</span>
                        <span class="bp">self</span><span class="o">.</span><span class="n">_save_sepset</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="p">(</span><span class="nb">frozenset</span><span class="p">(</span><span class="n">Z_test</span><span class="p">),</span> <span class="s2">&quot;nwm&quot;</span><span class="p">))</span>

                <span class="k">if</span> <span class="n">remove_CB</span><span class="p">:</span>

                    <span class="c1"># Remember the edge for removal</span>
                    <span class="n">pair_key</span><span class="p">,</span> <span class="n">new_link</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_pair_key_and_new_link</span><span class="p">(</span><span class="n">C</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">)</span>
                    <span class="n">out</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">pair_key</span><span class="p">,</span> <span class="n">new_link</span><span class="p">))</span>

            <span class="c1">###################################################################################</span>
            <span class="c1">### Part 3) of the rule ###########################################################</span>

            <span class="k">if</span> <span class="n">remove_AB</span> <span class="ow">or</span> <span class="n">remove_CB</span> <span class="ow">or</span> <span class="n">link_AB</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">&quot;-&quot;</span><span class="p">,</span> <span class="s2">&quot;x&quot;</span><span class="p">]</span> <span class="ow">or</span> <span class="n">link_CB</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">&quot;-&quot;</span><span class="p">,</span> <span class="s2">&quot;x&quot;</span><span class="p">]</span> <span class="ow">or</span> <span class="n">link_AB</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;x&quot;</span> <span class="ow">or</span> <span class="n">link_CB</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;x&quot;</span> <span class="ow">or</span> <span class="p">(</span><span class="n">link_AB</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;&gt;&quot;</span> <span class="ow">and</span> <span class="n">link_CB</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;&gt;&quot;</span><span class="p">):</span>
                <span class="k">continue</span>

            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_B_not_in_SepSet_AC</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">C</span><span class="p">):</span>

                <span class="c1"># Prepare the new links and save them to the output</span>
                <span class="k">if</span> <span class="n">link_AB</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;&gt;&quot;</span><span class="p">:</span>
                    <span class="n">new_link_AB</span> <span class="o">=</span> <span class="n">link_AB</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">link_AB</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;&gt;&quot;</span>
                    <span class="n">out</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_get_pair_key_and_new_link</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">new_link_AB</span><span class="p">))</span>

                <span class="n">new_link_CB</span> <span class="o">=</span> <span class="n">link_CB</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">link_CB</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;&gt;&quot;</span>
                <span class="k">if</span> <span class="n">link_CB</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;&gt;&quot;</span><span class="p">:</span>
                    <span class="n">out</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_get_pair_key_and_new_link</span><span class="p">(</span><span class="n">C</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">new_link_CB</span><span class="p">))</span>

        <span class="c1"># end for (A, B, C) in all_appropriate_triples</span>

        <span class="c1"># Return the output list</span>
        <span class="k">return</span> <span class="n">out</span>


    <span class="k">def</span> <span class="nf">_apply_ER00b</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">only_lagged</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return all orientations implied by orientation rule R0^prime b&quot;&quot;&quot;</span>

        <span class="c1"># Build the output list</span>
        <span class="n">out</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="c1"># Find all graphical structures that the rule applies to</span>
        <span class="n">triples_1</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_find_triples</span><span class="p">(</span><span class="n">pattern_ij</span><span class="o">=</span><span class="s1">&#39;**&gt;&#39;</span><span class="p">,</span> <span class="n">pattern_jk</span><span class="o">=</span><span class="s1">&#39;o!+&#39;</span><span class="p">,</span> <span class="n">pattern_ik</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">)</span>
        <span class="n">triples_2</span> <span class="o">=</span> <span class="p">[</span><span class="n">trip</span> <span class="k">for</span> <span class="n">trip</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_find_triples</span><span class="p">(</span><span class="n">pattern_ij</span><span class="o">=</span><span class="s1">&#39;**&gt;&#39;</span><span class="p">,</span> <span class="n">pattern_jk</span><span class="o">=</span><span class="s1">&#39;oR+&#39;</span><span class="p">,</span> <span class="n">pattern_ik</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_smaller</span><span class="p">(</span><span class="n">trip</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">trip</span><span class="p">[</span><span class="mi">2</span><span class="p">])]</span>
        <span class="n">triples_3</span> <span class="o">=</span> <span class="p">[</span><span class="n">trip</span> <span class="k">for</span> <span class="n">trip</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_find_triples</span><span class="p">(</span><span class="n">pattern_ij</span><span class="o">=</span><span class="s1">&#39;**&gt;&#39;</span><span class="p">,</span> <span class="n">pattern_jk</span><span class="o">=</span><span class="s1">&#39;oL+&#39;</span><span class="p">,</span> <span class="n">pattern_ik</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_smaller</span><span class="p">(</span><span class="n">trip</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">trip</span><span class="p">[</span><span class="mi">1</span><span class="p">])]</span>
        <span class="n">all_appropriate_triples</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">triples_1</span><span class="p">)</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="n">triples_2</span><span class="p">),</span> <span class="nb">set</span><span class="p">(</span><span class="n">triples_3</span><span class="p">))</span>

        <span class="c1"># Run through all appropriate graphical structures</span>
        <span class="k">for</span> <span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">C</span><span class="p">)</span> <span class="ow">in</span> <span class="n">all_appropriate_triples</span><span class="p">:</span>

            <span class="c1"># Unpack A, B, C</span>
            <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="o">=</span> <span class="n">A</span>
            <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="n">lag_j</span><span class="p">)</span> <span class="o">=</span> <span class="n">B</span>
            <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">lag_k</span><span class="p">)</span> <span class="o">=</span> <span class="n">C</span>

            <span class="k">if</span> <span class="n">only_lagged</span> <span class="ow">and</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">B</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
                <span class="k">continue</span>

            <span class="c1"># Get all weakly minimal separating sets in SepSet(A, C)</span>
            <span class="c1"># Remark: The non weakly minimal separating sets may be larger, that&#39;s why we disfavor them</span>
            <span class="n">sepsets</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_sepsets</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">)</span>
            <span class="n">sepsets</span> <span class="o">=</span> <span class="p">{</span><span class="n">Z</span> <span class="k">for</span> <span class="p">(</span><span class="n">Z</span><span class="p">,</span> <span class="n">status</span><span class="p">)</span> <span class="ow">in</span> <span class="n">sepsets</span> <span class="k">if</span> <span class="n">status</span> <span class="o">==</span> <span class="s2">&quot;wm&quot;</span><span class="p">}</span>

            <span class="c1">###################################################################################</span>
            <span class="c1">### Part 1) of the rule ###########################################################</span>

            <span class="n">remove_AB</span> <span class="o">=</span> <span class="kc">False</span>
            <span class="n">link_AB</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">)</span>

            <span class="c1"># i) Middle mark must not be &quot;x&quot; or &quot;-&quot;</span>
            <span class="k">if</span> <span class="n">link_AB</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="s1">&#39;-&#39;</span><span class="p">,</span> <span class="s1">&#39;x&#39;</span><span class="p">]:</span>
                <span class="c1"># Test A indep B given union(SepSet(A, C), intersection(def-anc(B), adj(B))) setminus{A, B} setminus{future of both A and B}</span>

                <span class="c1"># Conditioning on parents</span>
                <span class="n">Z_add</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_parents</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">)</span><span class="o">.</span><span class="n">difference</span><span class="p">({</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">})</span>

                <span class="c1"># Shift the lags appropriately</span>
                <span class="k">if</span> <span class="n">lag_i</span> <span class="o">&lt;=</span> <span class="n">lag_j</span><span class="p">:</span>
                    <span class="n">X</span> <span class="o">=</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span> <span class="o">-</span> <span class="n">lag_j</span><span class="p">)</span>
                    <span class="n">Y</span> <span class="o">=</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
                    <span class="n">delta_lag</span> <span class="o">=</span> <span class="n">lag_j</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="n">X</span> <span class="o">=</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="n">lag_j</span> <span class="o">-</span> <span class="n">lag_i</span><span class="p">)</span>
                    <span class="n">Y</span> <span class="o">=</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
                    <span class="n">delta_lag</span> <span class="o">=</span> <span class="n">lag_i</span>

                <span class="c1"># Run through all weakly minimal separating sets of A and C</span>
                <span class="k">for</span> <span class="n">Z</span> <span class="ow">in</span> <span class="n">sepsets</span><span class="p">:</span>

                    <span class="c1"># Construct the conditioning set to test</span>
                    <span class="n">Z_test</span> <span class="o">=</span> <span class="n">Z</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="n">Z_add</span><span class="p">)</span><span class="o">.</span><span class="n">difference</span><span class="p">({</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">})</span>
                    <span class="n">Z_test</span> <span class="o">=</span> <span class="p">{(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">-</span> <span class="n">delta_lag</span><span class="p">)</span> <span class="k">for</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">)</span> <span class="ow">in</span> <span class="n">Z_test</span> <span class="k">if</span> <span class="n">lag</span> <span class="o">-</span> <span class="n">delta_lag</span> <span class="o">&lt;=</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">lag</span> <span class="o">-</span> <span class="n">delta_lag</span> <span class="o">&gt;=</span> <span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">}</span>
                    <span class="n">Z_add2</span> <span class="o">=</span> <span class="p">{(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">-</span> <span class="n">delta_lag</span><span class="p">)</span> <span class="k">for</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">)</span> <span class="ow">in</span> <span class="n">Z_add</span><span class="o">.</span><span class="n">difference</span><span class="p">({</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">})</span> <span class="k">if</span> <span class="n">lag</span> <span class="o">-</span> <span class="n">delta_lag</span> <span class="o">&lt;=</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">lag</span> <span class="o">-</span> <span class="n">delta_lag</span> <span class="o">&gt;=</span> <span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">}</span>

                    <span class="c1"># Test conditional independence of X and Y given Z</span>
                    <span class="c1"># val, pval = self.cond_ind_test.run_test(X = [X], Y = [Y], Z = list(Z_test), tau_max = self.tau_max)</span>
                    <span class="n">val</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">dependent</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cond_ind_test</span><span class="o">.</span><span class="n">run_test</span><span class="p">(</span><span class="n">X</span> <span class="o">=</span> <span class="p">[</span><span class="n">X</span><span class="p">],</span> <span class="n">Y</span> <span class="o">=</span> <span class="p">[</span><span class="n">Y</span><span class="p">],</span> <span class="n">Z</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">Z_test</span><span class="p">),</span> 
                        <span class="n">tau_max</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">,</span> <span class="n">alpha_or_thres</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">pc_alpha</span><span class="p">)</span>

                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">:</span>
                        <span class="c1"># print(&quot;ER00b:    %s _|_ %s  |  Z_test = %s: val = %.2f / pval = % .4f&quot; %</span>
                        <span class="c1">#     (X, Y, &#39; &#39;.join([str(z) for z in list(Z_test)]), val, pval))</span>
                        <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ER00b:    </span><span class="si">%s</span><span class="s2"> _|_ </span><span class="si">%s</span><span class="s2">  |  Z_add = </span><span class="si">%s</span><span class="s2">, Z = </span><span class="si">%s</span><span class="s2">: val = </span><span class="si">%.2f</span><span class="s2"> / pval = </span><span class="si">% .4f</span><span class="s2">&quot;</span> <span class="o">%</span>
                            <span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="n">Z_add2</span><span class="p">]),</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="n">Z_test</span><span class="p">]),</span> <span class="n">val</span><span class="p">,</span> <span class="n">pval</span><span class="p">))</span>

                    <span class="c1"># Accordingly update dictionaries that keep track of the maximal p-value and the corresponding test statistic values and</span>
                    <span class="c1"># conditioning set cardinalities</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_update_pval_val_card_dicts</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">val</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">Z_test</span><span class="p">))</span>

                    <span class="c1"># Check whether test result was significant</span>
                    <span class="k">if</span> <span class="ow">not</span> <span class="n">dependent</span><span class="p">:</span> <span class="c1"># pval &gt; self.pc_alpha:</span>

                        <span class="c1"># Mark the edge from X to Y for removal and save sepset</span>
                        <span class="n">remove_AB</span> <span class="o">=</span> <span class="kc">True</span>
                        <span class="bp">self</span><span class="o">.</span><span class="n">_save_sepset</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="p">(</span><span class="nb">frozenset</span><span class="p">(</span><span class="n">Z_test</span><span class="p">),</span> <span class="s2">&quot;nwm&quot;</span><span class="p">))</span>

                <span class="k">if</span> <span class="n">remove_AB</span><span class="p">:</span>
                    <span class="c1"># Remember the edge for removal</span>
                    <span class="n">pair_key</span><span class="p">,</span> <span class="n">new_link</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_pair_key_and_new_link</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">)</span>
                    <span class="n">out</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">pair_key</span><span class="p">,</span> <span class="n">new_link</span><span class="p">))</span>

            <span class="c1">###################################################################################</span>
            <span class="c1">### Part 2) of the rule ###########################################################</span>

            <span class="k">if</span> <span class="n">only_lagged</span> <span class="ow">and</span> <span class="n">B</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
                <span class="k">continue</span>

            <span class="k">if</span> <span class="n">remove_AB</span> <span class="ow">or</span> <span class="n">link_AB</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;x&quot;</span><span class="p">:</span>
                <span class="k">continue</span>

            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_B_not_in_SepSet_AC</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">C</span><span class="p">):</span>

                <span class="c1"># Prepare the new link and save it to the output</span>
                <span class="n">link_CB</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">C</span><span class="p">,</span> <span class="n">B</span><span class="p">)</span>
                <span class="n">new_link_CB</span> <span class="o">=</span> <span class="n">link_CB</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">link_CB</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;&gt;&quot;</span>
                <span class="n">out</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_get_pair_key_and_new_link</span><span class="p">(</span><span class="n">C</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">new_link_CB</span><span class="p">))</span>

        <span class="c1"># end for (A, B, C) in all_appropriate_triples</span>

        <span class="c1"># Return the output list</span>
        <span class="k">return</span> <span class="n">out</span>


    <span class="k">def</span> <span class="nf">_apply_ER00c</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">only_lagged</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return all orientations implied by orientation rule R0^prime c&quot;&quot;&quot;</span>

        <span class="c1"># Build the output list</span>
        <span class="n">out</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="c1"># Find all graphical structures that the rule applies to</span>
        <span class="n">triples_1</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_find_triples</span><span class="p">(</span><span class="n">pattern_ij</span><span class="o">=</span><span class="s1">&#39;*-*&#39;</span><span class="p">,</span> <span class="n">pattern_jk</span><span class="o">=</span><span class="s1">&#39;o!+&#39;</span><span class="p">,</span> <span class="n">pattern_ik</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">)</span>
        <span class="n">triples_2</span> <span class="o">=</span> <span class="p">[</span><span class="n">trip</span> <span class="k">for</span> <span class="n">trip</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_find_triples</span><span class="p">(</span><span class="n">pattern_ij</span><span class="o">=</span><span class="s1">&#39;*-*&#39;</span><span class="p">,</span> <span class="n">pattern_jk</span><span class="o">=</span><span class="s1">&#39;oR+&#39;</span><span class="p">,</span> <span class="n">pattern_ik</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_smaller</span><span class="p">(</span><span class="n">trip</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">trip</span><span class="p">[</span><span class="mi">2</span><span class="p">])]</span>
        <span class="n">triples_3</span> <span class="o">=</span> <span class="p">[</span><span class="n">trip</span> <span class="k">for</span> <span class="n">trip</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_find_triples</span><span class="p">(</span><span class="n">pattern_ij</span><span class="o">=</span><span class="s1">&#39;*-*&#39;</span><span class="p">,</span> <span class="n">pattern_jk</span><span class="o">=</span><span class="s1">&#39;oL+&#39;</span><span class="p">,</span> <span class="n">pattern_ik</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">)</span>
                        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_smaller</span><span class="p">(</span><span class="n">trip</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">trip</span><span class="p">[</span><span class="mi">1</span><span class="p">])]</span>
        <span class="n">all_appropriate_triples</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">triples_1</span><span class="p">)</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="n">triples_2</span><span class="p">),</span> <span class="nb">set</span><span class="p">(</span><span class="n">triples_3</span><span class="p">))</span>

        <span class="c1"># Run through all appropriate graphical structures</span>
        <span class="k">for</span> <span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">C</span><span class="p">)</span> <span class="ow">in</span> <span class="n">all_appropriate_triples</span><span class="p">:</span>

            <span class="k">if</span> <span class="n">only_lagged</span> <span class="ow">and</span>  <span class="n">B</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
                <span class="k">continue</span>

            <span class="c1"># Check whether the rule applies</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_B_not_in_SepSet_AC</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">C</span><span class="p">):</span>

                <span class="c1"># Prepare the new link and append it to the output</span>
                <span class="n">link_CB</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">C</span><span class="p">,</span> <span class="n">B</span><span class="p">)</span>
                <span class="n">new_link_CB</span> <span class="o">=</span> <span class="n">link_CB</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">link_CB</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;&gt;&quot;</span>
                <span class="n">out</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_get_pair_key_and_new_link</span><span class="p">(</span><span class="n">C</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">new_link_CB</span><span class="p">))</span>

        <span class="c1"># end for (A, B, C) in all_appropriate_triples</span>

        <span class="c1"># Return the output list</span>
        <span class="k">return</span> <span class="n">out</span>


    <span class="k">def</span> <span class="nf">_apply_ER00d</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">only_lagged</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return all orientations implied by orientation rule R0^prime d&quot;&quot;&quot;</span>

        <span class="c1"># Build the output list</span>
        <span class="n">out</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="c1"># Find all graphical structures that the rule applies to</span>
        <span class="n">triples_1</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_find_triples</span><span class="p">(</span><span class="n">pattern_ij</span><span class="o">=</span><span class="s1">&#39;*-o&#39;</span><span class="p">,</span> <span class="n">pattern_jk</span><span class="o">=</span><span class="s1">&#39;o-*&#39;</span><span class="p">,</span> <span class="n">pattern_ik</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">)</span>
        <span class="n">triples_2</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_find_triples</span><span class="p">(</span><span class="n">pattern_ij</span><span class="o">=</span><span class="s1">&#39;*-&gt;&#39;</span><span class="p">,</span> <span class="n">pattern_jk</span><span class="o">=</span><span class="s1">&#39;o-*&#39;</span><span class="p">,</span> <span class="n">pattern_ik</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">)</span>
        <span class="n">all_appropriate_triples</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">triples_1</span><span class="p">)</span><span class="o">.</span><span class="n">union</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="n">triples_2</span><span class="p">))</span>

        <span class="c1"># Run through all appropriate graphical structures</span>
        <span class="k">for</span> <span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">C</span><span class="p">)</span> <span class="ow">in</span> <span class="n">all_appropriate_triples</span><span class="p">:</span>

            <span class="k">if</span> <span class="n">only_lagged</span> <span class="ow">and</span> <span class="p">(</span><span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">B</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="ow">and</span> <span class="n">B</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">]):</span>
                <span class="k">continue</span>

            <span class="c1"># Check whether the rule applies</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_B_not_in_SepSet_AC</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">C</span><span class="p">):</span>
                <span class="c1"># Prepare the new links and append them to the output</span>

                <span class="c1"># From C to B</span>
                <span class="k">if</span> <span class="ow">not</span> <span class="n">only_lagged</span> <span class="ow">or</span> <span class="n">B</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">!=</span> <span class="n">C</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
                    <span class="n">link_CB</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">C</span><span class="p">,</span> <span class="n">B</span><span class="p">)</span>
                    <span class="n">new_link_CB</span> <span class="o">=</span> <span class="n">link_CB</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">link_CB</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;&gt;&quot;</span>
                    <span class="n">out</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_get_pair_key_and_new_link</span><span class="p">(</span><span class="n">C</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">new_link_CB</span><span class="p">))</span>

                <span class="c1"># If needed, also fromA to B</span>
                <span class="n">link_AB</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">)</span>
                <span class="k">if</span> <span class="p">(</span><span class="ow">not</span> <span class="n">only_lagged</span> <span class="ow">or</span> <span class="n">A</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">!=</span> <span class="n">B</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="ow">and</span> <span class="n">link_AB</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;o&quot;</span><span class="p">:</span>
                    <span class="n">new_link_AB</span> <span class="o">=</span> <span class="n">link_AB</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">link_AB</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;&gt;&quot;</span>
                    <span class="n">out</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_get_pair_key_and_new_link</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">new_link_AB</span><span class="p">))</span>

        <span class="c1"># end for (A, B, C) in all_appropriate_triples</span>

        <span class="c1"># Return the output list</span>
        <span class="k">return</span> <span class="n">out</span>

    <span class="c1">########################################################################################################################</span>
    <span class="c1">########################################################################################################################</span>
    <span class="c1">########################################################################################################################</span>

    <span class="k">def</span> <span class="nf">_print_graph_dict</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Print all links in graph_dict&quot;&quot;&quot;</span>

        <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">):</span>
            <span class="k">for</span> <span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="n">link</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
                <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">link</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="p">(</span><span class="n">lag_i</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">j</span><span class="p">):</span>
                    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;(</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) </span><span class="si">{}</span><span class="s2"> </span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">,</span> <span class="n">link</span><span class="p">,</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>


    <span class="k">def</span> <span class="nf">_get_link</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Get the current link from node A to B&quot;&quot;&quot;</span>

        <span class="p">(</span><span class="n">var_A</span><span class="p">,</span> <span class="n">lag_A</span><span class="p">)</span> <span class="o">=</span> <span class="n">A</span>
        <span class="p">(</span><span class="n">var_B</span><span class="p">,</span> <span class="n">lag_B</span><span class="p">)</span> <span class="o">=</span> <span class="n">B</span>

        <span class="k">if</span> <span class="nb">abs</span><span class="p">(</span><span class="n">lag_A</span> <span class="o">-</span> <span class="n">lag_B</span><span class="p">)</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">:</span>
            <span class="k">return</span> <span class="s2">&quot;&quot;</span>
        <span class="k">elif</span> <span class="n">lag_A</span> <span class="o">&lt;=</span> <span class="n">lag_B</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">var_B</span><span class="p">][(</span><span class="n">var_A</span><span class="p">,</span> <span class="n">lag_A</span> <span class="o">-</span> <span class="n">lag_B</span><span class="p">)]</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_reverse_link</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">var_A</span><span class="p">][(</span><span class="n">var_B</span><span class="p">,</span> <span class="n">lag_B</span> <span class="o">-</span> <span class="n">lag_A</span><span class="p">)])</span>


    <span class="k">def</span> <span class="nf">_get_non_future_adj</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">node_list</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return all non-future adjacencies of all nodes in node_list&quot;&quot;&quot;</span>

        <span class="c1"># Build the output starting from an empty set</span>
        <span class="n">out</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>

        <span class="c1"># For each node W in node_list ...</span>
        <span class="k">for</span> <span class="n">A</span> <span class="ow">in</span> <span class="n">node_list</span><span class="p">:</span>
            <span class="c1"># Unpack A</span>
            <span class="p">(</span><span class="n">var_A</span><span class="p">,</span> <span class="n">lag_A</span><span class="p">)</span> <span class="o">=</span> <span class="n">A</span>
            <span class="c1"># Add all (current) non-future adjacencies of A to the set out</span>
            <span class="n">out</span> <span class="o">=</span> <span class="n">out</span><span class="o">.</span><span class="n">union</span><span class="p">({(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">lag_A</span><span class="p">)</span> <span class="k">for</span> <span class="p">((</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">),</span> <span class="n">link</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">var_A</span><span class="p">]</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">link</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">lag_A</span> <span class="o">&gt;=</span> <span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span><span class="p">})</span>

        <span class="c1"># Return the desired set</span>
        <span class="k">return</span> <span class="n">out</span>

    <span class="k">def</span> <span class="nf">_update_pval_val_card_dicts</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">pval</span><span class="p">,</span> <span class="n">val</span><span class="p">,</span> <span class="n">card</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;If &#39;pval&#39; is larger than the current maximal p-value across all previous independence tests for X and Y (stored in self.pval_max)</span>
<span class="sd">        then: Replace the current values stored in self.pval_max, self.pval_max_val, self.pval_max_card respectively by &#39;pval&#39;, &#39;val&#39;, and &#39;card&#39;.&quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="n">X</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">X</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">Y</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span>
            <span class="k">if</span> <span class="n">pval</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">pval_max</span><span class="p">[</span><span class="n">Y</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="n">X</span><span class="p">]:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">pval_max</span><span class="p">[</span><span class="n">Y</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="n">X</span><span class="p">]</span> <span class="o">=</span> <span class="n">pval</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">pval_max_val</span><span class="p">[</span><span class="n">Y</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="n">X</span><span class="p">]</span> <span class="o">=</span> <span class="n">val</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">pval_max_card</span><span class="p">[</span><span class="n">Y</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="n">X</span><span class="p">]</span> <span class="o">=</span> <span class="n">card</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">pval</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">pval_max</span><span class="p">[</span><span class="n">X</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="n">Y</span><span class="p">]:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">pval_max</span><span class="p">[</span><span class="n">X</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="n">Y</span><span class="p">]</span> <span class="o">=</span> <span class="n">pval</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">pval_max_val</span><span class="p">[</span><span class="n">X</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="n">Y</span><span class="p">]</span> <span class="o">=</span> <span class="n">val</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">pval_max_card</span><span class="p">[</span><span class="n">X</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="n">Y</span><span class="p">]</span> <span class="o">=</span> <span class="n">card</span>

    <span class="k">def</span> <span class="nf">_save_sepset</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">Z</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Save Z as separating sets of X and Y. Y is assumed to be at lag 0&quot;&quot;&quot;</span>

        <span class="c1"># Unpack X and Y</span>
        <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="o">=</span> <span class="n">X</span>
        <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="n">lag_j</span><span class="p">)</span> <span class="o">=</span> <span class="n">Y</span>

        <span class="k">assert</span> <span class="n">lag_j</span> <span class="o">==</span> <span class="mi">0</span>

        <span class="c1"># Save the sepset</span>
        <span class="k">if</span> <span class="n">lag_i</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">j</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">sepsets</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="n">X</span><span class="p">]</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">Z</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">sepsets</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">Y</span><span class="p">]</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">Z</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">_reverse_link</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">link</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Reverse a given link, taking care to replace &gt; with &lt; and vice versa&quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="n">link</span> <span class="o">==</span> <span class="s2">&quot;&quot;</span><span class="p">:</span>
            <span class="k">return</span> <span class="s2">&quot;&quot;</span>

        <span class="k">if</span> <span class="n">link</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;&gt;&quot;</span><span class="p">:</span>
            <span class="n">left_mark</span> <span class="o">=</span> <span class="s2">&quot;&lt;&quot;</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">left_mark</span> <span class="o">=</span> <span class="n">link</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>

        <span class="k">if</span> <span class="n">link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;&lt;&quot;</span><span class="p">:</span>
            <span class="n">right_mark</span> <span class="o">=</span> <span class="s2">&quot;&gt;&quot;</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">right_mark</span> <span class="o">=</span> <span class="n">link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>

        <span class="k">return</span> <span class="n">left_mark</span> <span class="o">+</span> <span class="n">link</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">right_mark</span>


    <span class="k">def</span> <span class="nf">_write_link</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">new_link</span><span class="p">,</span> <span class="n">verbosity</span> <span class="o">=</span> <span class="mi">0</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Write the information that the link from node A to node B takes the form of new_link into self.graph_dict. Neither is it assumed</span>
<span class="sd">        that at least of the nodes is at lag 0, nor must A be before B. If A and B are contemporaneous, also the link from B to A is written</span>
<span class="sd">        as the reverse of new_link&quot;&quot;&quot;</span>

        <span class="c1"># Unpack A and B</span>
        <span class="p">(</span><span class="n">var_A</span><span class="p">,</span> <span class="n">lag_A</span><span class="p">)</span> <span class="o">=</span> <span class="n">A</span>
        <span class="p">(</span><span class="n">var_B</span><span class="p">,</span> <span class="n">lag_B</span><span class="p">)</span> <span class="o">=</span> <span class="n">B</span>

        <span class="c1"># Write the link from A to B</span>
        <span class="k">if</span> <span class="n">lag_A</span> <span class="o">&lt;</span> <span class="n">lag_B</span><span class="p">:</span>

            <span class="k">if</span> <span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">{:10}</span><span class="s2"> (</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) </span><span class="si">{:3}</span><span class="s2"> (</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) ==&gt; (</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) </span><span class="si">{:3}</span><span class="s2"> (</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) &quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s2">&quot;Writing:&quot;</span><span class="p">,</span> <span class="n">var_A</span><span class="p">,</span> <span class="n">lag_A</span> <span class="o">-</span> <span class="n">lag_B</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">var_B</span><span class="p">][(</span><span class="n">var_A</span><span class="p">,</span> <span class="n">lag_A</span> <span class="o">-</span> <span class="n">lag_B</span><span class="p">)],</span> <span class="n">var_B</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">var_A</span><span class="p">,</span> <span class="n">lag_A</span> <span class="o">-</span> <span class="n">lag_B</span><span class="p">,</span> <span class="n">new_link</span><span class="p">,</span> <span class="n">var_B</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
                <span class="c1">#print(&quot;Replacing {:3} from ({},{:2}) to {} with {:3}&quot;.format(self.graph_dict[var_B][(var_A, lag_A - lag_B)], var_A, lag_A - lag_B, (var_B, 0), new_link))</span>

            <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">var_B</span><span class="p">][(</span><span class="n">var_A</span><span class="p">,</span> <span class="n">lag_A</span> <span class="o">-</span> <span class="n">lag_B</span><span class="p">)]</span> <span class="o">=</span> <span class="n">new_link</span>


        <span class="k">elif</span> <span class="n">lag_A</span> <span class="o">==</span> <span class="n">lag_B</span><span class="p">:</span>

            <span class="k">if</span> <span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">{:10}</span><span class="s2"> (</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) </span><span class="si">{:3}</span><span class="s2"> (</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) ==&gt; (</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) </span><span class="si">{:3}</span><span class="s2"> (</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) &quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s2">&quot;Writing:&quot;</span><span class="p">,</span> <span class="n">var_A</span><span class="p">,</span> <span class="n">lag_A</span> <span class="o">-</span> <span class="n">lag_B</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">var_B</span><span class="p">][(</span><span class="n">var_A</span><span class="p">,</span> <span class="mi">0</span><span class="p">)],</span> <span class="n">var_B</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">var_A</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">new_link</span><span class="p">,</span> <span class="n">var_B</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
                <span class="c1">#print(&quot;Replacing {:3} from ({},{:2}) to {} with {:3}&quot;.format(self.graph_dict[var_B][(var_A, 0)], var_A, 0, (var_B, 0), new_link))</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">{:10}</span><span class="s2"> (</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) </span><span class="si">{:3}</span><span class="s2"> (</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) ==&gt; (</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) </span><span class="si">{:3}</span><span class="s2"> (</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) &quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s2">&quot;Writing:&quot;</span><span class="p">,</span> <span class="n">var_B</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">var_A</span><span class="p">][(</span><span class="n">var_B</span><span class="p">,</span> <span class="mi">0</span><span class="p">)],</span> <span class="n">var_A</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">var_B</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_reverse_link</span><span class="p">(</span><span class="n">new_link</span><span class="p">),</span> <span class="n">var_A</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
                <span class="c1">#print(&quot;Replacing {:3} from ({},{:2}) to {} with {:3}&quot;.format(self.graph_dict[var_A][(var_B, 0)], var_B, 0, (var_A, 0), self._reverse_link(new_link)))</span>

            <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">var_B</span><span class="p">][(</span><span class="n">var_A</span><span class="p">,</span> <span class="mi">0</span><span class="p">)]</span> <span class="o">=</span> <span class="n">new_link</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">var_A</span><span class="p">][(</span><span class="n">var_B</span><span class="p">,</span> <span class="mi">0</span><span class="p">)]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_reverse_link</span><span class="p">(</span><span class="n">new_link</span><span class="p">)</span>

        <span class="k">else</span><span class="p">:</span>

            <span class="k">if</span> <span class="n">verbosity</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
                <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">{:10}</span><span class="s2"> (</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) </span><span class="si">{:3}</span><span class="s2"> (</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) ==&gt; (</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) </span><span class="si">{:3}</span><span class="s2"> (</span><span class="si">{}</span><span class="s2">,</span><span class="si">{:2}</span><span class="s2">) &quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s2">&quot;Writing:&quot;</span><span class="p">,</span> <span class="n">var_B</span><span class="p">,</span> <span class="n">lag_B</span> <span class="o">-</span> <span class="n">lag_A</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">var_A</span><span class="p">][(</span><span class="n">var_B</span><span class="p">,</span> <span class="n">lag_B</span> <span class="o">-</span> <span class="n">lag_A</span><span class="p">)],</span> <span class="n">var_A</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">var_B</span><span class="p">,</span> <span class="n">lag_B</span> <span class="o">-</span> <span class="n">lag_A</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_reverse_link</span><span class="p">(</span><span class="n">new_link</span><span class="p">),</span> <span class="n">var_A</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
                <span class="c1">#print(&quot;Replacing {:3} from ({},{:2}) to {} with {:3}&quot;.format(self.graph_dict[var_A][(var_B, lag_B - lag_A)], var_B, lag_B - lag_A, (var_A, 0), self._reverse_link(new_link)))</span>

            <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">var_A</span><span class="p">][(</span><span class="n">var_B</span><span class="p">,</span> <span class="n">lag_B</span> <span class="o">-</span> <span class="n">lag_A</span><span class="p">)]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_reverse_link</span><span class="p">(</span><span class="n">new_link</span><span class="p">)</span>


    <span class="k">def</span> <span class="nf">_get_sepsets</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;For two non-adjacent nodes, get the their separating stored in self.sepsets.&quot;&quot;&quot;</span>

        <span class="p">(</span><span class="n">var_A</span><span class="p">,</span> <span class="n">lag_A</span><span class="p">)</span> <span class="o">=</span> <span class="n">A</span>
        <span class="p">(</span><span class="n">var_B</span><span class="p">,</span> <span class="n">lag_B</span><span class="p">)</span> <span class="o">=</span> <span class="n">B</span>

        <span class="k">def</span> <span class="nf">_shift</span><span class="p">(</span><span class="n">Z</span><span class="p">,</span> <span class="n">lag_B</span><span class="p">):</span>
            <span class="k">return</span> <span class="nb">frozenset</span><span class="p">([(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">lag_B</span><span class="p">)</span> <span class="k">for</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">)</span> <span class="ow">in</span> <span class="n">Z</span><span class="p">])</span>

        <span class="k">if</span> <span class="n">lag_A</span> <span class="o">&lt;</span> <span class="n">lag_B</span><span class="p">:</span>
            <span class="n">out</span> <span class="o">=</span> <span class="p">{(</span><span class="n">_shift</span><span class="p">(</span><span class="n">Z</span><span class="p">,</span> <span class="n">lag_B</span><span class="p">),</span> <span class="n">status</span><span class="p">)</span> <span class="k">for</span> <span class="p">(</span><span class="n">Z</span><span class="p">,</span> <span class="n">status</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">sepsets</span><span class="p">[</span><span class="n">var_B</span><span class="p">][(</span><span class="n">var_A</span><span class="p">,</span> <span class="n">lag_A</span> <span class="o">-</span> <span class="n">lag_B</span><span class="p">)]}</span>
        <span class="k">elif</span> <span class="n">lag_A</span> <span class="o">&gt;</span> <span class="n">lag_B</span><span class="p">:</span>
            <span class="n">out</span> <span class="o">=</span> <span class="p">{(</span><span class="n">_shift</span><span class="p">(</span><span class="n">Z</span><span class="p">,</span> <span class="n">lag_A</span><span class="p">),</span> <span class="n">status</span><span class="p">)</span> <span class="k">for</span> <span class="p">(</span><span class="n">Z</span><span class="p">,</span> <span class="n">status</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">sepsets</span><span class="p">[</span><span class="n">var_A</span><span class="p">][(</span><span class="n">var_B</span><span class="p">,</span> <span class="n">lag_B</span> <span class="o">-</span> <span class="n">lag_A</span><span class="p">)]}</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">out</span> <span class="o">=</span> <span class="p">{(</span><span class="n">_shift</span><span class="p">(</span><span class="n">Z</span><span class="p">,</span> <span class="n">lag_A</span><span class="p">),</span> <span class="n">status</span><span class="p">)</span> <span class="k">for</span> <span class="p">(</span><span class="n">Z</span><span class="p">,</span> <span class="n">status</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">sepsets</span><span class="p">[</span><span class="nb">max</span><span class="p">(</span><span class="n">var_A</span><span class="p">,</span> <span class="n">var_B</span><span class="p">)][(</span><span class="nb">min</span><span class="p">(</span><span class="n">var_A</span><span class="p">,</span> <span class="n">var_B</span><span class="p">),</span> <span class="mi">0</span><span class="p">)]}</span>

        <span class="k">return</span> <span class="n">out</span>


    <span class="k">def</span> <span class="nf">_initialize_full_graph</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        The function _get_na_pds_t() needs to know the future adjacencies of a given node, not only the non-future adjacencies that are</span>
<span class="sd">        stored in self.graph_dict. To aid this, this function initializes the dictionary graph_full_dict:</span>

<span class="sd">        self.graph_full_dict[j][(i, -tau_i)] contains all adjacencies of (j, 0), in particular those for which tau_i &lt; 0.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="c1"># Build from an empty nested dictionary</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">graph_full_dict</span> <span class="o">=</span> <span class="p">{</span><span class="n">j</span><span class="p">:</span> <span class="p">{}</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">)}</span>

        <span class="c1"># Run through the entire nested dictionary self.graph_dict</span>
        <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">):</span>
            <span class="k">for</span> <span class="p">((</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">),</span> <span class="n">link</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>

                <span class="k">if</span> <span class="n">link</span> <span class="o">!=</span> <span class="s2">&quot;&quot;</span><span class="p">:</span>
                    <span class="c1"># Add non-future adjacencies</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">graph_full_dict</span><span class="p">[</span><span class="n">j</span><span class="p">][(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">)]</span> <span class="o">=</span> <span class="n">link</span>

                    <span class="c1"># Add the future adjacencies </span>
                    <span class="k">if</span> <span class="n">lag</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">:</span>
                        <span class="bp">self</span><span class="o">.</span><span class="n">graph_full_dict</span><span class="p">[</span><span class="n">var</span><span class="p">][(</span><span class="n">j</span><span class="p">,</span> <span class="o">-</span><span class="n">lag</span><span class="p">)]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_reverse_link</span><span class="p">(</span><span class="n">link</span><span class="p">)</span>

        <span class="c1"># Return nothing</span>
        <span class="k">return</span> <span class="kc">None</span>


    <span class="k">def</span> <span class="nf">_get_pair_key_and_new_link</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">link_AB</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;The link from A to B takes the form link_AB. Bring this information into a form appropriate for the output of rule applications&quot;&quot;&quot;</span>

        <span class="p">(</span><span class="n">var_A</span><span class="p">,</span> <span class="n">lag_A</span><span class="p">)</span> <span class="o">=</span> <span class="n">A</span>
        <span class="p">(</span><span class="n">var_B</span><span class="p">,</span> <span class="n">lag_B</span><span class="p">)</span> <span class="o">=</span> <span class="n">B</span>

        <span class="k">if</span> <span class="n">lag_A</span> <span class="o">&lt;=</span> <span class="n">lag_B</span><span class="p">:</span>
            <span class="k">return</span> <span class="p">((</span><span class="n">var_A</span><span class="p">,</span> <span class="n">var_B</span><span class="p">,</span> <span class="n">lag_A</span> <span class="o">-</span> <span class="n">lag_B</span><span class="p">),</span> <span class="n">link_AB</span><span class="p">)</span>
        <span class="k">elif</span> <span class="n">lag_A</span> <span class="o">&gt;</span> <span class="n">lag_B</span><span class="p">:</span>
            <span class="k">return</span> <span class="p">((</span><span class="n">var_B</span><span class="p">,</span> <span class="n">var_A</span><span class="p">,</span> <span class="n">lag_B</span> <span class="o">-</span> <span class="n">lag_A</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">_reverse_link</span><span class="p">(</span><span class="n">link_AB</span><span class="p">))</span>


    <span class="k">def</span> <span class="nf">_match_link</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">pattern</span><span class="p">,</span> <span class="n">link</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Matches pattern including wildcards with link.&quot;&quot;&quot;</span>
        
        <span class="k">if</span> <span class="n">pattern</span> <span class="o">==</span> <span class="s1">&#39;&#39;</span> <span class="ow">or</span> <span class="n">link</span> <span class="o">==</span> <span class="s1">&#39;&#39;</span><span class="p">:</span>
            <span class="k">return</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">pattern</span> <span class="o">==</span> <span class="n">link</span> <span class="k">else</span> <span class="kc">False</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">left_mark</span><span class="p">,</span> <span class="n">middle_mark</span><span class="p">,</span> <span class="n">right_mark</span> <span class="o">=</span> <span class="n">pattern</span>
            <span class="k">if</span> <span class="n">left_mark</span> <span class="o">!=</span> <span class="s1">&#39;*&#39;</span><span class="p">:</span>
                <span class="k">if</span> <span class="n">left_mark</span> <span class="o">==</span> <span class="s1">&#39;+&#39;</span><span class="p">:</span>
                    <span class="k">if</span> <span class="n">link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="s1">&#39;&lt;&#39;</span><span class="p">,</span> <span class="s1">&#39;o&#39;</span><span class="p">]:</span> <span class="k">return</span> <span class="kc">False</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="k">if</span> <span class="n">link</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="n">left_mark</span><span class="p">:</span> <span class="k">return</span> <span class="kc">False</span>

            <span class="k">if</span> <span class="n">right_mark</span> <span class="o">!=</span> <span class="s1">&#39;*&#39;</span><span class="p">:</span>
                <span class="k">if</span> <span class="n">right_mark</span> <span class="o">==</span> <span class="s1">&#39;+&#39;</span><span class="p">:</span>
                    <span class="k">if</span> <span class="n">link</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="s1">&#39;&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;o&#39;</span><span class="p">]:</span> <span class="k">return</span> <span class="kc">False</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="k">if</span> <span class="n">link</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">!=</span> <span class="n">right_mark</span><span class="p">:</span> <span class="k">return</span> <span class="kc">False</span>    
            
            <span class="k">if</span> <span class="n">middle_mark</span> <span class="o">!=</span> <span class="s1">&#39;*&#39;</span> <span class="ow">and</span> <span class="n">link</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">!=</span> <span class="n">middle_mark</span><span class="p">:</span> <span class="k">return</span> <span class="kc">False</span>    
                       
            <span class="k">return</span> <span class="kc">True</span>


    <span class="k">def</span> <span class="nf">_dict2graph</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Convert self.graph_dict to graph array of shape (N, N, self.tau_max + 1).&quot;&quot;&quot;</span>

        <span class="n">graph</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">((</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="o">+</span> <span class="mi">1</span><span class="p">),</span> <span class="n">dtype</span><span class="o">=</span><span class="s1">&#39;U3&#39;</span><span class="p">)</span>
        <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">):</span>
            <span class="k">for</span> <span class="n">adj</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">j</span><span class="p">]:</span>
                <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="o">=</span> <span class="n">adj</span>
                <span class="n">graph</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="nb">abs</span><span class="p">(</span><span class="n">lag_i</span><span class="p">)]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_dict</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="n">adj</span><span class="p">]</span>

        <span class="k">return</span> <span class="n">graph</span>


    <span class="k">def</span> <span class="nf">_find_adj</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">graph</span><span class="p">,</span> <span class="n">node</span><span class="p">,</span> <span class="n">patterns</span><span class="p">,</span> <span class="n">exclude</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">ignore_time_bounds</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Find adjacencies of node matching patterns.&quot;&quot;&quot;</span>
        
        <span class="c1"># Setup</span>
        <span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span> <span class="o">=</span> <span class="n">node</span>
        <span class="k">if</span> <span class="n">exclude</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> <span class="n">exclude</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="n">patterns</span><span class="p">)</span> <span class="o">==</span> <span class="nb">str</span><span class="p">:</span>
            <span class="n">patterns</span> <span class="o">=</span> <span class="p">[</span><span class="n">patterns</span><span class="p">]</span>

        <span class="c1"># Init</span>
        <span class="n">adj</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="c1"># Find adjacencies going forward/contemp</span>
        <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">lag_ik</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="o">*</span><span class="n">np</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="n">graph</span><span class="p">[</span><span class="n">i</span><span class="p">,:,:])):</span>  
            <span class="n">matches</span> <span class="o">=</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_match_link</span><span class="p">(</span><span class="n">patt</span><span class="p">,</span> <span class="n">graph</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="n">lag_ik</span><span class="p">])</span> <span class="k">for</span> <span class="n">patt</span> <span class="ow">in</span> <span class="n">patterns</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">np</span><span class="o">.</span><span class="n">any</span><span class="p">(</span><span class="n">matches</span><span class="p">):</span>
                <span class="n">match</span> <span class="o">=</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">lag_i</span> <span class="o">+</span> <span class="n">lag_ik</span><span class="p">)</span>
                <span class="k">if</span> <span class="n">match</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">adj</span> <span class="ow">and</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">lag_i</span> <span class="o">+</span> <span class="n">lag_ik</span><span class="p">)</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">exclude</span> <span class="ow">and</span> <span class="p">(</span><span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="o">&lt;=</span> <span class="n">lag_i</span> <span class="o">+</span> <span class="n">lag_ik</span> <span class="o">&lt;=</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">ignore_time_bounds</span><span class="p">):</span>
                    <span class="n">adj</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">match</span><span class="p">)</span>
        
        <span class="c1"># Find adjacencies going backward/contemp</span>
        <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">lag_ki</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="o">*</span><span class="n">np</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="n">graph</span><span class="p">[:,</span><span class="n">i</span><span class="p">,:])):</span>  
            <span class="n">matches</span> <span class="o">=</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_match_link</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_reverse_link</span><span class="p">(</span><span class="n">patt</span><span class="p">),</span> <span class="n">graph</span><span class="p">[</span><span class="n">k</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">lag_ki</span><span class="p">])</span> <span class="k">for</span> <span class="n">patt</span> <span class="ow">in</span> <span class="n">patterns</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">np</span><span class="o">.</span><span class="n">any</span><span class="p">(</span><span class="n">matches</span><span class="p">):</span>
                <span class="n">match</span> <span class="o">=</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">lag_i</span> <span class="o">-</span> <span class="n">lag_ki</span><span class="p">)</span>
                <span class="k">if</span> <span class="n">match</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">adj</span> <span class="ow">and</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">lag_i</span> <span class="o">-</span> <span class="n">lag_ki</span><span class="p">)</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">exclude</span> <span class="ow">and</span> <span class="p">(</span><span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="o">&lt;=</span> <span class="n">lag_i</span> <span class="o">-</span> <span class="n">lag_ki</span> <span class="o">&lt;=</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">ignore_time_bounds</span><span class="p">):</span>
                    <span class="n">adj</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">match</span><span class="p">)</span>
     
        <span class="k">return</span> <span class="n">adj</span>
        

    <span class="k">def</span> <span class="nf">_is_match</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">graph</span><span class="p">,</span> <span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">pattern_ij</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Check whether the link between X and Y agrees with pattern_ij&quot;&quot;&quot;</span>

        <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="o">=</span> <span class="n">X</span>
        <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="n">lag_j</span><span class="p">)</span> <span class="o">=</span> <span class="n">Y</span>
        <span class="n">tauij</span> <span class="o">=</span> <span class="n">lag_j</span> <span class="o">-</span> <span class="n">lag_i</span>
        <span class="k">if</span> <span class="nb">abs</span><span class="p">(</span><span class="n">tauij</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="n">graph</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">2</span><span class="p">]:</span>
            <span class="k">return</span> <span class="kc">False</span>
        <span class="k">return</span> <span class="p">((</span><span class="n">tauij</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_match_link</span><span class="p">(</span><span class="n">pattern_ij</span><span class="p">,</span> <span class="n">graph</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="n">tauij</span><span class="p">]))</span> <span class="ow">or</span>
               <span class="p">(</span><span class="n">tauij</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_match_link</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_reverse_link</span><span class="p">(</span><span class="n">pattern_ij</span><span class="p">),</span> <span class="n">graph</span><span class="p">[</span><span class="n">j</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="nb">abs</span><span class="p">(</span><span class="n">tauij</span><span class="p">)])))</span>


    <span class="k">def</span> <span class="nf">_find_triples</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">pattern_ij</span><span class="p">,</span> <span class="n">pattern_jk</span><span class="p">,</span> <span class="n">pattern_ik</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Find triples (i, lag_i), (j, lag_j), (k, lag_k) that match patterns.&quot;&quot;&quot;</span>
  
        <span class="c1"># Graph as array makes it easier to search forward AND backward in time</span>
        <span class="n">graph</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dict2graph</span><span class="p">()</span>

        <span class="c1"># print(graph[:,:,0])</span>
        <span class="c1"># print(graph[:,:,1])</span>
        <span class="c1"># print(&quot;matching &quot;, pattern_ij, pattern_jk, pattern_ik)</span>

        <span class="n">matched_triples</span> <span class="o">=</span> <span class="p">[]</span>
                
        <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">N</span><span class="p">):</span>
            <span class="c1"># Set lag_i = 0 without loss of generality, will be adjusted at end</span>
            <span class="n">lag_i</span> <span class="o">=</span> <span class="mi">0</span>
            <span class="n">adjacencies_i</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_find_adj</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="n">pattern_ij</span><span class="p">)</span>
            <span class="c1"># print(i, adjacencies_i)</span>
            <span class="k">for</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="n">lag_j</span><span class="p">)</span> <span class="ow">in</span> <span class="n">adjacencies_i</span><span class="p">:</span>

                <span class="n">adjacencies_j</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_find_adj</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="n">lag_j</span><span class="p">),</span> <span class="n">pattern_jk</span><span class="p">,</span>
                                          <span class="n">exclude</span><span class="o">=</span><span class="p">[(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)])</span>
                <span class="c1"># print(j, adjacencies_j)</span>
                <span class="k">for</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">lag_k</span><span class="p">)</span> <span class="ow">in</span> <span class="n">adjacencies_j</span><span class="p">:</span>
                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_match</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">lag_k</span><span class="p">),</span> <span class="n">pattern_ik</span><span class="p">):</span>                            
                        <span class="c1"># Now use stationarity and shift triple such that the right-most</span>
                        <span class="c1"># node (on a line t=..., -2, -1, 0, 1, 2, ...) is at lag 0</span>
                        <span class="n">righmost_lag</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">lag_i</span><span class="p">,</span> <span class="n">lag_j</span><span class="p">,</span> <span class="n">lag_k</span><span class="p">)</span>
                        <span class="n">match</span> <span class="o">=</span> <span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span> <span class="o">-</span> <span class="n">righmost_lag</span><span class="p">),</span> 
                                 <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="n">lag_j</span> <span class="o">-</span> <span class="n">righmost_lag</span><span class="p">),</span>
                                 <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">lag_k</span> <span class="o">-</span> <span class="n">righmost_lag</span><span class="p">))</span>
                        <span class="n">largest_lag</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">lag_i</span> <span class="o">-</span> <span class="n">righmost_lag</span><span class="p">,</span> <span class="n">lag_j</span> <span class="o">-</span> <span class="n">righmost_lag</span><span class="p">,</span> <span class="n">lag_k</span> <span class="o">-</span> <span class="n">righmost_lag</span><span class="p">)</span>
                        <span class="k">if</span> <span class="n">match</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">matched_triples</span> <span class="ow">and</span> \
                            <span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="o">&lt;=</span> <span class="n">largest_lag</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">:</span>
                            <span class="n">matched_triples</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">match</span><span class="p">)</span>                       
                
        <span class="k">return</span> <span class="n">matched_triples</span>  


    <span class="k">def</span> <span class="nf">_find_quadruples</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">pattern_ij</span><span class="p">,</span> <span class="n">pattern_jk</span><span class="p">,</span> <span class="n">pattern_ik</span><span class="p">,</span> 
                               <span class="n">pattern_il</span><span class="p">,</span> <span class="n">pattern_jl</span><span class="p">,</span> <span class="n">pattern_kl</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Find quadruples (i, lag_i), (j, lag_j), (k, lag_k), (l, lag_l) that match patterns.&quot;&quot;&quot;</span>
  
        <span class="c1"># We assume this later</span>
        <span class="k">assert</span> <span class="n">pattern_il</span> <span class="o">!=</span> <span class="s1">&#39;&#39;</span>

        <span class="c1"># Graph as array makes it easier to search forward AND backward in time</span>
        <span class="n">graph</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dict2graph</span><span class="p">()</span>

        <span class="n">matched_quadruples</span> <span class="o">=</span> <span class="p">[]</span>
                
        <span class="c1"># First get triple ijk</span>
        <span class="n">ijk_triples</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_find_triples</span><span class="p">(</span><span class="n">pattern_ij</span><span class="p">,</span> <span class="n">pattern_jk</span><span class="p">,</span> <span class="n">pattern_ik</span><span class="p">)</span>

        <span class="k">for</span> <span class="n">triple</span> <span class="ow">in</span> <span class="n">ijk_triples</span><span class="p">:</span>
            <span class="c1"># Unpack triple</span>
            <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="n">lag_j</span><span class="p">),</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">lag_k</span><span class="p">)</span> <span class="o">=</span> <span class="n">triple</span>

            <span class="c1"># Search through adjacencies</span>
            <span class="n">adjacencies</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_find_adj</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="n">pattern_il</span><span class="p">,</span>
                                          <span class="n">exclude</span><span class="o">=</span><span class="p">[(</span><span class="n">j</span><span class="p">,</span> <span class="n">lag_j</span><span class="p">),</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">lag_k</span><span class="p">)]))</span>
            <span class="k">if</span> <span class="n">pattern_jl</span> <span class="o">!=</span> <span class="s1">&#39;&#39;</span><span class="p">:</span>
                <span class="n">adjacencies</span> <span class="o">=</span> <span class="n">adjacencies</span><span class="o">.</span><span class="n">intersection</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span>
                                <span class="bp">self</span><span class="o">.</span><span class="n">_find_adj</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="n">lag_j</span><span class="p">),</span> <span class="n">pattern_jl</span><span class="p">,</span>
                                          <span class="n">exclude</span><span class="o">=</span><span class="p">[(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">lag_k</span><span class="p">)])))</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">adjacencies</span> <span class="o">=</span> <span class="nb">set</span><span class="p">([</span><span class="n">adj</span> <span class="k">for</span> <span class="n">adj</span> <span class="ow">in</span> <span class="n">adjacencies</span> 
                                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_match</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="n">lag_j</span><span class="p">),</span> <span class="n">adj</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)])</span>

            <span class="k">if</span> <span class="n">pattern_kl</span> <span class="o">!=</span> <span class="s1">&#39;&#39;</span><span class="p">:</span>
                <span class="n">adjacencies</span> <span class="o">=</span> <span class="n">adjacencies</span><span class="o">.</span><span class="n">intersection</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span>
                                <span class="bp">self</span><span class="o">.</span><span class="n">_find_adj</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">lag_k</span><span class="p">),</span> <span class="n">pattern_kl</span><span class="p">,</span>
                                          <span class="n">exclude</span><span class="o">=</span><span class="p">[(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">),</span> <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="n">lag_j</span><span class="p">)])))</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">adjacencies</span> <span class="o">=</span> <span class="nb">set</span><span class="p">([</span><span class="n">adj</span> <span class="k">for</span> <span class="n">adj</span> <span class="ow">in</span> <span class="n">adjacencies</span> 
                                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_match</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">lag_k</span><span class="p">),</span> <span class="n">adj</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)])</span>

            <span class="k">for</span> <span class="n">adj</span> <span class="ow">in</span> <span class="n">adjacencies</span><span class="p">:</span>
                <span class="p">(</span><span class="n">l</span><span class="p">,</span> <span class="n">lag_l</span><span class="p">)</span> <span class="o">=</span> <span class="n">adj</span>
                    
                <span class="c1"># Now use stationarity and shift quadruple such that the right-most</span>
                <span class="c1"># node (on a line t=..., -2, -1, 0, 1, 2, ...) is at lag 0</span>
                <span class="n">righmost_lag</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">lag_i</span><span class="p">,</span> <span class="n">lag_j</span><span class="p">,</span> <span class="n">lag_k</span><span class="p">,</span> <span class="n">lag_l</span><span class="p">)</span>
                <span class="n">match</span> <span class="o">=</span> <span class="p">((</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span> <span class="o">-</span> <span class="n">righmost_lag</span><span class="p">),</span> 
                         <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="n">lag_j</span> <span class="o">-</span> <span class="n">righmost_lag</span><span class="p">),</span>
                         <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">lag_k</span> <span class="o">-</span> <span class="n">righmost_lag</span><span class="p">),</span>
                         <span class="p">(</span><span class="n">l</span><span class="p">,</span> <span class="n">lag_l</span> <span class="o">-</span> <span class="n">righmost_lag</span><span class="p">),</span>
                         <span class="p">)</span>
                <span class="n">largest_lag</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">lag_i</span> <span class="o">-</span> <span class="n">righmost_lag</span><span class="p">,</span> 
                                  <span class="n">lag_j</span> <span class="o">-</span> <span class="n">righmost_lag</span><span class="p">,</span> 
                                  <span class="n">lag_k</span> <span class="o">-</span> <span class="n">righmost_lag</span><span class="p">,</span>
                                  <span class="n">lag_l</span> <span class="o">-</span> <span class="n">righmost_lag</span><span class="p">,</span>
                                  <span class="p">)</span>
                <span class="k">if</span> <span class="n">match</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">matched_quadruples</span> <span class="ow">and</span> \
                    <span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="o">&lt;=</span> <span class="n">largest_lag</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">:</span>
                    <span class="n">matched_quadruples</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">match</span><span class="p">)</span>                       
                
        <span class="k">return</span> <span class="n">matched_quadruples</span> 


    <span class="k">def</span> <span class="nf">_get_R4_discriminating_paths</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">triple</span><span class="p">,</span> <span class="n">max_length</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">inf</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Find all discriminating paths starting from triple&quot;&quot;&quot;</span>

        <span class="k">def</span> <span class="nf">_search</span><span class="p">(</span><span class="n">path_taken</span><span class="p">,</span> <span class="n">max_length</span><span class="p">):</span>

            <span class="c1"># Get the last visited node and its link to Y</span>
            <span class="n">last_node</span> <span class="o">=</span> <span class="n">path_taken</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
            <span class="n">link_to_Y</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">last_node</span><span class="p">,</span> <span class="n">path_taken</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>

            <span class="c1"># Base Case: If the current path is a discriminating path, return it as single entry of a list</span>
            <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">path_taken</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">3</span> <span class="ow">and</span> <span class="n">link_to_Y</span> <span class="o">==</span> <span class="s2">&quot;&quot;</span><span class="p">:</span>
                <span class="k">return</span> <span class="p">[</span><span class="n">path_taken</span><span class="p">]</span>            

            <span class="c1"># If the current path is not a discriminating path, continue the path</span>
            <span class="n">paths</span> <span class="o">=</span> <span class="p">[]</span>

            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">last_node</span><span class="p">,</span> <span class="n">path_taken</span><span class="p">[</span><span class="o">-</span><span class="mi">2</span><span class="p">])[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;&lt;&quot;</span> <span class="ow">and</span> <span class="n">link_to_Y</span> <span class="o">==</span> <span class="s2">&quot;--&gt;&quot;</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">path_taken</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">max_length</span><span class="p">:</span>

                <span class="c1"># Search through all adjacencies of the last node</span>
                <span class="k">for</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_full_dict</span><span class="p">[</span><span class="n">last_node</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span>

                    <span class="c1"># Build the next node and get its link to the previous</span>
                    <span class="n">next_node</span> <span class="o">=</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">last_node</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
                    <span class="n">next_link</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">next_node</span><span class="p">,</span> <span class="n">last_node</span><span class="p">)</span>

                    <span class="c1"># Check whether this node can be visited</span>
                    <span class="k">if</span> <span class="n">next_node</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">next_node</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="ow">and</span> <span class="n">next_node</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">path_taken</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_match_link</span><span class="p">(</span><span class="s2">&quot;*-&gt;&quot;</span><span class="p">,</span> <span class="n">next_link</span><span class="p">):</span>

                        <span class="c1"># Recursive call</span>
                        <span class="n">paths</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">_search</span><span class="p">(</span><span class="n">path_taken</span><span class="p">[:]</span> <span class="o">+</span> <span class="p">[</span><span class="n">next_node</span><span class="p">],</span> <span class="n">max_length</span><span class="p">))</span>

            <span class="c1"># Return the list of discriminating paths</span>
            <span class="k">return</span> <span class="n">paths</span>

        <span class="c1"># Unpack the triple</span>
        <span class="p">(</span><span class="n">W</span><span class="p">,</span> <span class="n">V</span><span class="p">,</span> <span class="n">Y</span><span class="p">)</span> <span class="o">=</span> <span class="n">triple</span>

        <span class="c1"># Return all discriminating paths starting at this triple</span>
        <span class="k">return</span> <span class="n">_search</span><span class="p">([</span><span class="n">Y</span><span class="p">,</span> <span class="n">V</span><span class="p">,</span> <span class="n">W</span><span class="p">],</span> <span class="n">max_length</span><span class="p">)</span>


    <span class="k">def</span> <span class="nf">_get_potentially_directed_uncovered_paths</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">start_node</span><span class="p">,</span> <span class="n">end_node</span><span class="p">,</span> <span class="n">initial_allowed_patterns</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Find all potentiall directed uncoverged paths from start_node to end_node whose first link takes one the forms specified by</span>
<span class="sd">        initial_allowed_patters&quot;&quot;&quot;</span>

        <span class="k">assert</span> <span class="n">start_node</span> <span class="o">!=</span> <span class="n">end_node</span>

        <span class="c1"># Function for recursive search of potentially directed uncovered paths</span>
        <span class="k">def</span> <span class="nf">_search</span><span class="p">(</span><span class="n">end_node</span><span class="p">,</span> <span class="n">path_taken</span><span class="p">,</span> <span class="n">allowed_patterns</span><span class="p">):</span>

            <span class="c1"># List for outputting potentially directed uncovered paths</span>
            <span class="n">paths</span> <span class="o">=</span> <span class="p">[]</span>

            <span class="c1"># The last visited note becomes the new start_node</span>
            <span class="n">start_node</span> <span class="o">=</span> <span class="n">path_taken</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>

            <span class="c1"># Base case: End node has been reached</span>
            <span class="k">if</span> <span class="n">start_node</span> <span class="o">==</span> <span class="n">end_node</span><span class="p">:</span>
                <span class="n">paths</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">path_taken</span><span class="p">)</span>

            <span class="c1"># Recursive build case</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="c1"># Run through the adjacencies of start_node</span>
                <span class="c1">#for next_node in self.graph_full_dict[start_node[0]]:</span>
                <span class="k">for</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">graph_full_dict</span><span class="p">[</span><span class="n">start_node</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span>

                    <span class="n">next_node</span> <span class="o">=</span> <span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">lag</span> <span class="o">+</span> <span class="n">start_node</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>

                    <span class="c1"># Consider only nodes that ...</span>
                    <span class="c1"># ... are within the allowed time frame</span>
                    <span class="k">if</span> <span class="n">next_node</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&lt;</span> <span class="o">-</span><span class="bp">self</span><span class="o">.</span><span class="n">tau_max</span> <span class="ow">or</span> <span class="n">next_node</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
                        <span class="k">continue</span>
                    <span class="c1"># ... have not been visited yet</span>
                    <span class="k">if</span> <span class="n">next_node</span> <span class="ow">in</span> <span class="n">path_taken</span><span class="p">:</span>
                        <span class="k">continue</span>
                    <span class="c1"># ... are non-adjacent to the node before start_node</span>
                    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">path_taken</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="mi">2</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">path_taken</span><span class="p">[</span><span class="o">-</span><span class="mi">2</span><span class="p">],</span> <span class="n">next_node</span><span class="p">)</span> <span class="o">!=</span> <span class="s2">&quot;&quot;</span><span class="p">:</span>
                        <span class="k">continue</span>
                    <span class="c1"># ... whose link with start_node matches one of the allowed patters</span>
                    <span class="n">link</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_link</span><span class="p">(</span><span class="n">start_node</span><span class="p">,</span> <span class="n">next_node</span><span class="p">)</span>
                    <span class="k">if</span> <span class="ow">not</span> <span class="nb">any</span><span class="p">([</span><span class="bp">self</span><span class="o">.</span><span class="n">_match_link</span><span class="p">(</span><span class="n">pattern</span> <span class="o">=</span> <span class="n">pattern</span><span class="p">,</span> <span class="n">link</span> <span class="o">=</span> <span class="n">link</span><span class="p">)</span> <span class="k">for</span> <span class="n">pattern</span> <span class="ow">in</span> <span class="n">allowed_patterns</span><span class="p">]):</span>
                        <span class="k">continue</span>

                    <span class="c1"># Determine the allowed patters for the next recursive call</span>
                    <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_match_link</span><span class="p">(</span><span class="n">pattern</span><span class="o">=</span><span class="s1">&#39;o*o&#39;</span><span class="p">,</span> <span class="n">link</span><span class="o">=</span><span class="n">link</span><span class="p">):</span>
                        <span class="n">new_allowed_patters</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;o*o&quot;</span><span class="p">,</span> <span class="s2">&quot;o*&gt;&quot;</span><span class="p">,</span> <span class="s2">&quot;-*&gt;&quot;</span><span class="p">]</span>
                    <span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">_match_link</span><span class="p">(</span><span class="n">pattern</span><span class="o">=</span><span class="s1">&#39;o*&gt;&#39;</span><span class="p">,</span> <span class="n">link</span><span class="o">=</span><span class="n">link</span><span class="p">)</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_match_link</span><span class="p">(</span><span class="n">pattern</span><span class="o">=</span><span class="s1">&#39;-*&gt;&#39;</span><span class="p">,</span> <span class="n">link</span><span class="o">=</span><span class="n">link</span><span class="p">):</span>
                        <span class="n">new_allowed_patters</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;-*&gt;&quot;</span><span class="p">]</span>

                    <span class="c1"># Determine the new path taken</span>
                    <span class="n">new_path_taken</span> <span class="o">=</span> <span class="n">path_taken</span><span class="p">[:]</span> <span class="o">+</span> <span class="p">[</span><span class="n">next_node</span><span class="p">]</span>

                    <span class="c1"># Recursive call</span>
                    <span class="n">paths</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">_search</span><span class="p">(</span><span class="n">end_node</span><span class="p">,</span> <span class="n">new_path_taken</span><span class="p">,</span> <span class="n">new_allowed_patters</span><span class="p">))</span>

            <span class="c1"># Output list of potentially directed uncovered paths</span>
            <span class="k">return</span> <span class="n">paths</span>

        <span class="c1"># end def _search(end_node, path_taken, allowed_patterns)</span>

        <span class="c1"># Output potentially directed uncovered paths</span>
        <span class="n">paths</span> <span class="o">=</span> <span class="n">_search</span><span class="p">(</span><span class="n">end_node</span><span class="p">,</span> <span class="p">[</span><span class="n">start_node</span><span class="p">],</span> <span class="n">initial_allowed_patterns</span><span class="p">)</span>
        <span class="k">return</span> <span class="p">[</span><span class="n">path</span> <span class="k">for</span> <span class="n">path</span> <span class="ow">in</span> <span class="n">paths</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">path</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">2</span><span class="p">]</span>


    <span class="k">def</span> <span class="nf">_sort_search_set</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">search_set</span><span class="p">,</span> <span class="n">reference_node</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Sort the nodes in search_set by their values in self.pval_max_val with respect to the reference_node. Nodes with higher absolute</span>
<span class="sd">        values appear earlier&quot;&quot;&quot;</span>

        <span class="n">sort_by_potential_minus_infs</span> <span class="o">=</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_get_pval_max_val</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">reference_node</span><span class="p">)</span> <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">search_set</span><span class="p">]</span>
        <span class="n">sort_by</span> <span class="o">=</span> <span class="p">[(</span><span class="n">np</span><span class="o">.</span><span class="n">abs</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="k">if</span> <span class="n">value</span> <span class="o">!=</span> <span class="o">-</span><span class="n">np</span><span class="o">.</span><span class="n">inf</span> <span class="k">else</span> <span class="mi">0</span><span class="p">)</span> <span class="k">for</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">sort_by_potential_minus_infs</span><span class="p">]</span>

        <span class="k">return</span> <span class="p">[</span><span class="n">x</span> <span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">sort_by</span><span class="p">,</span> <span class="n">search_set</span><span class="p">),</span> <span class="n">reverse</span> <span class="o">=</span> <span class="kc">True</span><span class="p">)]</span>

    <span class="k">def</span> <span class="nf">_get_pval_max_val</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return the test statistic value of that independence test for X and Y which, among all such tests, has the largest p-value.&quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="n">X</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">X</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">Y</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">pval_max_val</span><span class="p">[</span><span class="n">Y</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="n">X</span><span class="p">]</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">pval_max_val</span><span class="p">[</span><span class="n">X</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="n">Y</span><span class="p">]</span>    

    <span class="k">def</span> <span class="nf">_delete_sepsets</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Delete all separating sets of X and Y. Y is assumed to be at lag 0&quot;&quot;&quot;</span>

        <span class="c1"># Unpack X and Y</span>
        <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">lag_i</span><span class="p">)</span> <span class="o">=</span> <span class="n">X</span>
        <span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="n">lag_j</span><span class="p">)</span> <span class="o">=</span> <span class="n">Y</span>

        <span class="k">assert</span> <span class="n">lag_j</span> <span class="o">==</span> <span class="mi">0</span>

        <span class="c1"># Save the sepset</span>
        <span class="k">if</span> <span class="n">lag_i</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">j</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">sepsets</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="n">X</span><span class="p">]</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">sepsets</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">Y</span><span class="p">]</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span></div>


<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>

    <span class="kn">from</span> <span class="nn">tigramite.independence_tests.parcorr</span> <span class="kn">import</span> <span class="n">ParCorr</span>
    <span class="kn">import</span> <span class="nn">tigramite.data_processing</span> <span class="k">as</span> <span class="nn">pp</span>
    <span class="kn">from</span> <span class="nn">tigramite.toymodels</span> <span class="kn">import</span> <span class="n">structural_causal_processes</span> <span class="k">as</span> <span class="n">toys</span>
    <span class="kn">import</span> <span class="nn">tigramite.plotting</span> <span class="k">as</span> <span class="nn">tp</span>
    <span class="kn">from</span> <span class="nn">matplotlib</span> <span class="kn">import</span> <span class="n">pyplot</span> <span class="k">as</span> <span class="n">plt</span>

    <span class="c1"># Example process to play around with</span>
    <span class="c1"># Each key refers to a variable and the incoming links are supplied</span>
    <span class="c1"># as a list of format [((var, -lag), coeff, function), ...]</span>
    <span class="k">def</span> <span class="nf">lin_f</span><span class="p">(</span><span class="n">x</span><span class="p">):</span> <span class="k">return</span> <span class="n">x</span>
    <span class="k">def</span> <span class="nf">nonlin_f</span><span class="p">(</span><span class="n">x</span><span class="p">):</span> <span class="k">return</span> <span class="p">(</span><span class="n">x</span> <span class="o">+</span> <span class="mf">5.</span> <span class="o">*</span> <span class="n">x</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="n">x</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">/</span> <span class="mf">20.</span><span class="p">))</span>

    <span class="n">links</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">:</span> <span class="p">[((</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">),</span> <span class="mf">0.9</span><span class="p">,</span> <span class="n">lin_f</span><span class="p">),</span> <span class="p">((</span><span class="mi">3</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">),</span> <span class="o">-</span><span class="mf">0.6</span><span class="p">,</span> <span class="n">lin_f</span><span class="p">)],</span>
             <span class="mi">1</span><span class="p">:</span> <span class="p">[((</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">),</span> <span class="mf">0.9</span><span class="p">,</span> <span class="n">lin_f</span><span class="p">),</span> <span class="p">((</span><span class="mi">3</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">),</span> <span class="mf">0.6</span><span class="p">,</span> <span class="n">lin_f</span><span class="p">)],</span>
             <span class="mi">2</span><span class="p">:</span> <span class="p">[((</span><span class="mi">2</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">),</span> <span class="mf">0.9</span><span class="p">,</span> <span class="n">lin_f</span><span class="p">),</span> <span class="p">((</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">),</span> <span class="mf">0.6</span><span class="p">,</span> <span class="n">lin_f</span><span class="p">)],</span>
             <span class="mi">3</span><span class="p">:</span> <span class="p">[],</span>
             <span class="p">}</span>

    <span class="n">full_data</span><span class="p">,</span> <span class="n">nonstat</span> <span class="o">=</span> <span class="n">toys</span><span class="o">.</span><span class="n">structural_causal_process</span><span class="p">(</span><span class="n">links</span><span class="p">,</span>
                        <span class="n">T</span><span class="o">=</span><span class="mi">1000</span><span class="p">,</span> <span class="n">seed</span><span class="o">=</span><span class="mi">7</span><span class="p">)</span>
    
    <span class="c1"># We now remove variable 3 which plays the role of a hidden confounder</span>
    <span class="n">data</span> <span class="o">=</span> <span class="n">full_data</span><span class="p">[:,</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]]</span>

    <span class="c1"># Data must be array of shape (time, variables)</span>
    <span class="nb">print</span><span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">shape</span><span class="p">)</span>
    <span class="n">dataframe</span> <span class="o">=</span> <span class="n">pp</span><span class="o">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
    <span class="n">cond_ind_test</span> <span class="o">=</span> <span class="n">ParCorr</span><span class="p">(</span><span class="n">significance</span><span class="o">=</span><span class="s1">&#39;fixed_thres&#39;</span><span class="p">)</span>
    <span class="n">lpcmci</span> <span class="o">=</span> <span class="n">LPCMCI</span><span class="p">(</span><span class="n">dataframe</span><span class="o">=</span><span class="n">dataframe</span><span class="p">,</span> <span class="n">cond_ind_test</span><span class="o">=</span><span class="n">cond_ind_test</span><span class="p">)</span>
    <span class="n">results</span> <span class="o">=</span> <span class="n">lpcmci</span><span class="o">.</span><span class="n">run_lpcmci</span><span class="p">(</span><span class="n">tau_max</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">pc_alpha</span><span class="o">=</span><span class="mf">0.01</span><span class="p">)</span>

    <span class="c1"># # For a proper causal interpretation of the graph see the paper!</span>
    <span class="c1"># print(results[&#39;graph&#39;])</span>
    <span class="c1"># tp.plot_graph(graph=results[&#39;graph&#39;], val_matrix=results[&#39;val_matrix&#39;])</span>
    <span class="c1"># plt.show()</span>

    <span class="c1"># results = lpcmci.run_sliding_window_of(</span>
    <span class="c1">#     window_step=499, window_length=500,</span>
    <span class="c1">#     method=&#39;run_lpcmci&#39;, method_args={&#39;tau_max&#39;:1})</span>
</pre></div>

          </div>
          
        </div>
      </div>
      <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
        <div class="sphinxsidebarwrapper">
<h1 class="logo"><a href="../../index.html">Tigramite</a></h1>








<h3>Navigation</h3>

<div class="relations">
<h3>Related Topics</h3>
<ul>
  <li><a href="../../index.html">Documentation overview</a><ul>
  <li><a href="../index.html">Module code</a><ul>
  </ul></li>
  </ul></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
  <h3 id="searchlabel">Quick search</h3>
    <div class="searchformwrapper">
    <form class="search" action="../../search.html" method="get">
      <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
      <input type="submit" value="Go" />
    </form>
    </div>
</div>
<script>document.getElementById('searchbox').style.display = "block"</script>








        </div>
      </div>
      <div class="clearer"></div>
    </div>
    <div class="footer">
      &copy;2023, Jakob Runge.
      
      |
      Powered by <a href="http://sphinx-doc.org/">Sphinx 5.0.2</a>
      &amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
      
    </div>

    

    
  </body>
</html>